Rails Validation Test Helpers
Posted by Jonathan on June 10, 2007 at 11:22 AM
I’ve written a couple test helpers that I’ve found to be pretty useful when testing ActiveRecord validations. Just add them to your RAILS_ROOT/test/test_helper.rb file.
The assert_errors_on method takes an object and a hash of attributes and the validation errors that they should have.
The assert_no_errors_on method takes an object and a list of attributes that should not have any validation errors.
1 def assert_errors_on(object, errors = {}) 2 assert !object.valid? 3 errors.each do |attribute, error| 4 assert_equal error.to_a.sort, object.errors.on(attribute).to_a.sort, "Error on #{attribute}" 5 end 6 end 7 8 def assert_no_errors_on(object, *attributes) 9 object.valid? 10 attributes.each { |attribute| assert_nil object.errors.on(attribute), "Error on #{attribute}" } 11 end
You can then use them like this:
1 require File.dirname(__FILE__) + '/../test_helper' 2 3 class PersonTest < Test::Unit::TestCase 4 def test_should_require_unique_email_address 5 # Using assert_errors_on method 6 person = Person.new :email_address => "cosmo@sprockets.com" 7 assert_errors_on person, :email_address => "has already been taken" 8 9 # Doing the same thing but without the assert_errors_on method 10 person = Person.new :email_address => "cosmo@sprockets.com" 11 assert !person.valid? 12 assert_equal "has already been taken", person.errors.on(:email_address) 13 14 # Using assert_no_errors on method 15 person = Person.new :email_address => "john.smith@example.com" 16 assert_no_errors_on person, :email_address 17 18 # Doing the same thing but without the assert_no_errors_on method 19 person = Person.new :email_address => "john.smith@example.com" 20 person.valid? 21 assert_nil person.errors.on(:email_address) 22 end 23 24 # We can test other attributes independently as well 25 26 def test_should_require_a_first_name 27 person = Person.new 28 assert_errors_on person, :first_name => "can't be blank" 29 30 person = Person.new :first_name => "Jonathan" 31 assert_no_errors_on :person, :first_name 32 end 33 34 def test_should_require_a_last_name 35 person = Person.new 36 assert_errors_on person, :last_name => "can't be blank" 37 38 person = Person.new :last_name => "Younger" 39 assert_no_errors_on :person, :last_name 40 end 41 42 def test_should_blah_blah_blah 43 ... 44 end 45 end
Updated 2007-11-28: Added additional attribute tests to show that the attributes can be tested in isolation without regards to ensuring that all of the attributes have to be valid for testing to work.
Updated 2007-09-14: Added code for showing what the tests would look like by not using the test helpers.
Comments
There are 3 comments on this post. Post yours →
Thanks for this simple yet useful helper methods! I have one question though: shouldn’t line 9 be “assert object.valid?”.
For the assert_no_errors_on method we are only checking if there are no errors on a particular attribute or set of attributes. The object may be valid but it is likely that it is not valid because other attributes that we are not checking may have errors.
If we did do “assert object.valid?” here we’d have to ensure that all attributes of the object were valid and not just the particular ones we are interested in testing at this time.
The reason why we wouldn’t want to ensure that all the attributes are valid here is for testing isolation. By being able to test each attribute independently of the others we can setup different tests for each attribute. I’ve updated the post to show an example of this.
Hope that helps and I’ve explained that well enough.
Thanks, Jonathan.
I found out that object.valid? validates the object. I was wondering why you included it, if you weren’t checking its value, but now I know that else object.validate wouldn’t be run.
Post a comment
Required fields in bold.