Picture of stu

How Not to Test Validations, Part 3

  • Posted By Stuart Halloway on July 15, 2007

This is Part 3 of the preview for "Keeping Tests Dry" at next week's erubycon.

Several people have commented with improvements to the code shown in Part 1 and Part 2. I will respond to some of these in the final installment, but first this: What if you could declare validation tests, just like you declare the validations themselves?

class ContactTest < Test::Unit::TestCase
  test_validates_presence_of :name, :email
end

This is nice and DRY: all future arguments about exactly what to assert, or why, can be settled in one place--the body of the validates_presence_of method. Here is a possible implementation:

  # TODO: eliminate the dependency @tested
  def self.test_validates_presence_of(*field_symbols)
    field_symbols.each do |field_symbol|
      field = field_symbol.to_s
      define_method("test_#{field}_required") do
        @tested.send("#{field}=", nil)
        assert !@tested.valid?, "Validation failed due to missing required field #{field}"
        field_errors = @tested.errors.on(field_symbol)
        assert_not_nil field_errors, "Validation did not run on field #{field}"
        error_message = ActiveRecord::Errors.default_error_messages[:blank]
        assert field_errors.include?(error_message), "Incorrect validation message for field #{field}"
      end
    end
  end

How would you improve this method? (More to follow...)

Comments
  1. Michael SchuerigJuly 15, 2007 @ 03:18 PM

    In my opinion, you should not be writing validations like that in the first place. Instead, I recommend using one of the plugins that automatically translate database constraints to validations. Of course, that only works for validations that can be expressed as database constraints, the others still have to be written and tested manually.

    What about testing the validations derived from the database? For one, I don’t write tests for these. Database constraints are as close to declarative as anything could be: NOT NULL, varchar(30) and so on.

  2. Patrick ReaganJuly 15, 2007 @ 08:44 PM

    Very nice – I’ve really enjoyed working with testing macros in Test::Unit for a while now. We started playing around with the Shoulda plugin from the ThoughtBot team. I have some issues with how they choose to write their macros, but the benefit of the plugin is really in allowing developers to define their own.

    Now if I could only find something similar for RSpec…