Never been to DZone Snippets before?

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

Testing Rails Validations (See related posts)

#
# 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 on this post

JoeSniff posts on Apr 01, 2008 at 05:56
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.
JoeSniff posts on Apr 01, 2008 at 06:13
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

You need to create an account or log in to post comments to this site.


Click here to browse all 5059 code snippets

Related Posts