How Not to Test Validations, Part 3

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...)

Get In Touch