ValidAttribute is a minimalist matcher for validation BDD.
Supported ORMs
- ActiveModel based (ActiveRecord >= 3.0, Mongoid >= 2.0, MongoMapper >= 0.9)
- ActiveRecord <= 2.3
- DataMapper
- Custom (with compatible API, see below)
If you're using RSpec just add the valid_attribute to your Gemfile AFTER rspec gem.
gem'valid_attribute'Then add it to your spec_helper.rb
require'valid_attribute'or if you're using Test::Unit, you must use Thoughtbot's shoulda-context
# Gemfilegem'shoulda-context'# test_helper.rbrequire'shoulda-context'require'valid_attribute'If you want to you use it with MiniTest::Spec you can use either shoulda-context (see above) or minitest-matchers:
# Gemfilegem'minitest-matchers'# test_helper.rbrequire'valid_attribute'Instead of having validation specific matchers ValidAttribute only cares if the attribute is valid under certain circumstances
classUserincludeActiveModel::Validationsattr_accessor:email,:name,:passwordvalidates:email,:format=>{:with=>/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i}validates:name,:length=>{:minimum=>5}validates:password,:confirmation=>true,:presence=>trueend# RSpecdescribeUserdo# The .when method can take any number of values that you want to passit{shouldhave_valid(:email).when('test@test.com','test+spam@gmail.com')}it{should_nothave_valid(:email).when('fail',123)}it{shouldhave_valid(:name).when('TestName')}it{should_nothave_valid(:name).when('Test')}# Because 'should' works off the the 'subject' in RSpec we can set other values if necessary for a given validation testdescribe'password'dobefore{subject.password_confirmation='password'}it{shouldhave_valid(:password).when('password')}it{should_nothave_valid(:password).when(nil)}end# Using .when is optional. Without it, the existing value is examined.it{should_nothave_valid(:email)}end# TestUnitrequire'shoulda/context'classUserTest < Test::Unit::TestCase# The .when method can take any number of values that you want to passshouldhave_valid(:email).when('test@test.com','test+spam@gmail.com')should_nothave_valid(:email).when('fail',123)shouldhave_valid(:name).when('TestName')should_nothave_valid(:name).when('Test')# Because 'shoulda-context' works off the 'subject' we can set other values if necessary for a given validation testcontext'password'dosubject{User.new(:password_confirmation=>'password')}shouldhave_valid(:password).when('password')should_nothave_valid(:password).when(nil)end# Using .when is optional. Without it, the existing value is examined.should_nothave_valid(:email)end# Minitest::Matchersrequire'minitest/matchers'describeUserdosubject{User.new}it{musthave_valid(:email).when('test@test.com','test+spam@gmail.com')}it{wonthave_valid(:email).when('fail',123)}it{musthave_valid(:name).when('TestName')}it{wonthave_valid(:name).when('Test')}describe'password'dosubject{User.new.tap{ |u| u.password_confirmation="password"}}it{musthave_valid(:password).when('password')}it{wonthave_valid(:password).when(nil)}endendYour model should respond to the following methods:
valid?- only used to generate errors on the modelerrors- should be a Hash of attributes that have the invalid attributes as keys.
The following would be a compatible (albeit unrealistic) model:
classUserattr_accessor:namedeferrors{:name=>["can't be blank"]}enddefvalid?falseendend# encoding: utf-8# RSpecdescribeUserdolet(:names){['TestName','Test-name',"O'Namey",'Maček']}it{shouldhave_valid(:first_name).when *names}it{shouldhave_valid(:last_name).when *names}endIf you feel that the setters are mutating parts of the object when testing multiple values you can force the test subject be cloned in between each test
it{shouldhave_valid(:name).when('Brian').clone}Be aware the cloning can cause some unpredicatable results and may lead to more pain than help
DockYard, LLC © 2012


