How Not to Test Validations, Part 1

  • Posted By Stuart Halloway on July 13, 2007

One of the things I will look at in "Keeping Tests Dry" at next week's erubycon is various ways people test ActiveRecord validations.

Here's one bad idea:

def test_contact_requires_name
  c = Contact.new
  err = assert_raise(ActiveRecord::RecordInvalid) {
    c.save!
  }
  assert_equal "Validation failed: Name can't be blank", 
                err.message
end

What's wrong with this example? (More to follow...)

Comments
  1. TomJuly 13, 2007 @ 09:44 PM

    Asserting on the text of the flash message makes the test brittle. Checking for errors on a particular attribute would be better…in case you ever wanted to customize the message…or the rails default message changes for some reason….

  2. John WulffJuly 13, 2007 @ 11:01 PM

    If more than one error rears its head that message isn’t going to match even though the validation that you’re looking to test is probably still doing its job.

    I’ve written a small plugin that I use to test validations that deals with this problem.

    http://validation-assertions.googlecode.com/svn/trunk/validation_assertions/lib/validation_assertions.rb

  3. Blake WattersJuly 14, 2007 @ 03:03 AM

    There’s no point in coupling the test to the database, as its both slow and imprecise. A better solution would be to just call assert !c.valid?, then assert_equal “can’t be blank”, c.errors.on(:name). Then you avoid the trip to the database, expensive exception raising, and all before/after hooks associated with the object life-cycle (not what you are testing).

    Your example is also not insulated from change, as the error message will grow as new validations are added that make newly initialized Contacts invalid.

    By the way, heya Stu!

  4. Luke RedpathJuly 14, 2007 @ 11:56 AM

    You are testing the format of the error message, not the presence of the validation.

  5. Sammy LarbiJuly 14, 2007 @ 04:17 PM

    I don’t like the hardcoded error message. What if it changes?