DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Testing Rails Validations

01.17.2006
| 6612 views |
  • submit to reddit
        
#
# Useful for testing Rails ActiveRecord validations. For more information see:
# http://wiseheartdesign.com/articles/2006/01/16/testing-rails-validations/
#
module ValidationTestHelper
  def assert_valid(field, message, *values)
    __model_check__
    values.each do |value|
      o = __setup_model__(field, value)
      if o.valid?
        assert_block { true }
      else
        messages = [o.errors[field]].flatten
        assert_block("unexpected invalid field <#{o.class}##{field}>, value: <#{value.inspect}>, errors: <#{o.errors[field].inspect}>.") { false }
      end
    end
  end
  
  def assert_invalid(field, message, *values)
    __model_check__
    values.each do |value|
      o = __setup_model__(field, value)
      if o.valid?
        assert_block("field <#{o.class}##{field}> should be invalid for value <#{value.inspect}> with message <#{message.inspect}>") { false }
      else
        messages = [o.errors[field]].flatten
        assert_block("field <#{o.class}##{field}> with value <#{value.inspect}> expected validation error <#{message.inspect}>, but got errors <#{messages.inspect}>") { messages.include?(message) }
      end
    end
  end
  
  def __model_check__
    raise "@model must be assigned in order to use validation assertions" if @model.nil?
    
    o = @model.dup
    raise "@model must be valid before calling a validation assertion, instead @model contained the following errors #{o.errors.instance_variable_get('@errors').inspect}" unless o.valid?
  end
  
  def __setup_model__(field, value)
    o = @model.dup
    attributes = o.instance_variable_get('@attributes')
    o.instance_variable_set('@attributes', attributes.dup)
    o.send("#{field}=", value)
    o
  end
end
    

Comments

Joseph Wilk replied on Tue, 2008/04/01 - 5:38am

Changing @model.dup to @model.clone Fixes this bug. Clone copies the whole object state, while dup does not. Fixed code: def __setup_model__(field, value) o = @model.clone attributes = o.instance_variable_get('@attributes') o.instance_variable_set('@attributes', attributes.dup) o.send("#{field}=", value) o end Joseph Wilk http://www.joesniff.co.uk

Joseph Wilk replied on Tue, 2008/04/01 - 5:38am

Ruby: 1.8 Rails: 2.0.2 I have a bug with this code. When methods are invoked on the return o object of __setup_model__ they are directed to @model rather than o. I have a presence validation on one of my model fields validates_presence_of :title, :message => "required" We call: assert_invalid :title, "required", "", nil Which in turn calls: __setup_model__(:title,"") def __setup_model__(field, value) o = @model.dup attributes = o.instance_variable_get('@attributes') o.instance_variable_set('@attributes', attributes.dup) o.send("#{field}=", value) o end pp o.valid? => true. This should be false, "".empty? is true so presence test should fail. The valid method is being called on the @model, which is valid.