Search code examples
ruby-on-railsruby-on-rails-3rspecrspec2rspec-rails

Rails 3.1, RSpec: testing model validations


I have started my journey with TDD in Rails and have run into a small issue regarding tests for model validations that I can't seem to find a solution to. Let's say I have a User model,

class User < ActiveRecord::Base
  validates :username, :presence => true
end

and a simple test

it "should require a username" do
  User.new(:username => "").should_not be_valid
end

This correctly tests the presence validation, but what if I want to be more specific? For example, testing full_messages on the errors object..

it "should require a username" do
  user = User.create(:username => "")
  user.errors[:username].should ~= /can't be blank/
end

My concern about the initial attempt (using should_not be_valid) is that RSpec won't produce a descriptive error message. It simply says "expected valid? to return false, got true." However, the second test example has a minor drawback: it uses the create method instead of the new method in order to get at the errors object.

I would like my tests to be more specific about what they're testing, but at the same time not have to touch a database.

Anyone have any input?


Solution

  • CONGRATULATIONS on you endeavor into TDD with ROR I promise once you get going you will not look back.

    The simplest quick and dirty solution will be to generate a new valid model before each of your tests like this:

     before(:each) do
        @user = User.new
        @user.username = "a valid username"
     end
    

    BUT what I suggest is you set up factories for all your models that will generate a valid model for you automatically and then you can muddle with individual attributes and see if your validation. I like to use FactoryGirl for this:

    Basically once you get set up your test would look something like this:

    it "should have valid factory" do
        FactoryGirl.build(:user).should be_valid
    end
    
    it "should require a username" do
        FactoryGirl.build(:user, :username => "").should_not be_valid
    end
    

    Here is a good railscast that explains it all better than me:


    UPDATE: As of version 3.0 the syntax for factory girl has changed. I have amended my sample code to reflect this.