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

Merb | Sequel | RSpec - Validations Testing Support

10.21.2008
| 5515 views |
  • submit to reddit
        Having got so hacked off trying to test validations by slamming correct and or incorrect values into models and then calling valid? and then checking for errors on the attribute I decided i needed proper validation reflection. Nicely, Sequel does supply you with Model.validations but its limited use since the actual validation values get crammed into a Proc. These few little nuggets not only makes my spec files SO much simpler (these are damn simple checks after all), it also gives me more confidence that I'm not creating brittle spec files. Comments welcome, ideas good, patches best.

## SEQUEL MONKEY PATCH (LOADED BY Merb::BootLoader.before_app_loads)
module Sequel
  class Model
    class << self

      # define our own nice reflection accessor
      def validation_reflection(attribute)
        return nil if @validation_reflection.nil?
        @validation_reflection[attribute]
      end

      # make sure we can still get to the original sequel method
      alias_method :sequel_validates_each, :validates_each

      # define our replacement validation method, capture the options and pass through
      def validates_each(*args, &block)
        hash = ((@validation_reflection ||= {})[args.first] ||= [])
        hash << { args.last[:tag] => eval("opts", block.binding) }
        sequel_validates_each(*args, &block)
      end

    end
  end
end

## RSPEC VALIDATION HELPERS
def required_attributes(*attrs)
  kind = self.described_type
  attrs.to_a.each do |a|
    it "should require a value for the #{a} attribute" do
      kind.validation_reflection(a).should_not be_nil
      kind.validation_reflection(a).select { |v| v[:presence] }.should_not be_empty
    end
  end  
end

def unique_attributes(*attrs)
  kind = self.described_type
  attrs.to_a.each do |a|
    it "should require the value for the #{a} attribute to be unique" do
      kind.validation_reflection(a).should_not be_nil
      kind.validation_reflection(a).select { |v| v[:uniqueness] }.should_not be_empty
    end
  end
end

def minimum_length_attributes(attrs)
  kind = self.described_type
  attrs.each do |k, l|
    it "should require that the #{k} attribute be at least #{l} characters long" do
      kind.validation_reflection(k).should_not be_nil
      kind.validation_reflection(k).select { |v| 
        v[:"length-minimum"] && v[:"length-minimum"][:minimum] == l ||
        v[:"length-is"] && v[:"length-is"][:is] == l
      }.should_not be_empty
    end
  end
end

def maximum_length_attributes(attrs)
  kind = self.described_type
  attrs.each do |k, l|
    it "should require that the #{k} attribute be at most #{l} characters long" do
      kind.validation_reflection(k).should_not be_nil
      kind.validation_reflection(k).select { |v| 
        v[:"length-maximum"] && v[:"length-maximum"][:maximum] == l ||
        v[:"length-is"] && v[:"length-is"][:is] == l
      }.should_not be_empty
    end
  end
end

## SAMPLE IN MODEL CHECKS
describe Model do

  required_attributes :name, :symbol
  unique_attributes :symbol
  minimum_length_attributes :name => 5, :symbol => 3
  maximum_length_attributes :name => 30, :symbol => 3

end