views:

444

answers:

4

What's the best practices way to test that a model is valid in rails?

For example, if I have a User model that validates the uniqueness of an email_address property, how do I check that posting the form returned an error (or better yet, specifically returned an error for that field).

I feel like this should be something obvious, but as I'm quickly finding out, I still don't quite have the vocabulary required to effectively google ruby questions.

+2  A: 

http://thoughtbot.com/projects/shoulda/

Shoulda includes macros for testing things like validators along with many other things. Worth checking out for TDD.

Ben Hughes
Shoulda rocks! Really helpful plugin for improving test suites and writing DRY tests.
Simone Carletti
+2  A: 

The easiest way would probably be:

class UserEmailAddressDuplicateTest < ActiveSupport::TestCase
  def setup
    @email = "[email protected]"
    @user1, @user2 = User.create(:email => @email), User.new(:email => @email)
  end

  def test_user_should_not_be_valid_given_duplicate_email_addresses
    assert [email protected]?
  end

  def test_user_should_produce_error_for_duplicate_email_address
    # Test for the default error message.
    assert_equal "has already been taken", @user2.errors.on(:email)
  end
end

Of course it's possible that you don't want to create a separate test case for this behaviour, in which case you could duplicate the logic in the setup method and include it in both tests (or put it in a private method).

Alternatively you could store the first (reference) user in a fixture such as fixtures/users.yml, and simply instantiate a new user with a duplicate address in each test.

Refactor as you see fit!

molf
+1  A: 

Testing the model via unit tests is, of course, step one. However, that doesn't necessarily guarantee that the user will get the feedback they need.

Section 4 of the Rails Guide on Testing has a lot of good information on functional testing (i.e. testing controllers and views). You have a couple of basic options here: check that the flash has a message in it about the error, or use assert_select to find the actual HTML elements that should have been generated in case of an error. The latter is really the only way to test that the user will actually get the message.

mcl
+1  A: 

errors.on is what you want

http://api.rubyonrails.org/classes/ActiveRecord/Errors.html#M002496

@obj.errors.on(:email) will return nil if field is valid, and the error messages either in a String or Array of Strings if there are one or more errors.

Omar Qureshi