module Shoulda::ActiveRecord::Matchers
def allow_mass_assignment_of(value)
it { should allow_mass_assignment_of(:first_name) }
it { should_not allow_mass_assignment_of(:password) }
Ensures that the attribute can be set on mass update.
def allow_mass_assignment_of(value) AllowMassAssignmentOfMatcher.new(value) end
def allow_value(value)
it { should allow_value("isbn 1 2345 6789 0").for(:isbn) }
it { should_not allow_value('bad').for(:isbn) }
Example:
translation for :invalid.
errors.on(:attribute). Regexp or string. Defaults to the
* with_message - value the test expects to find in
Options:
Ensures that the attribute can be set to the given value.
def allow_value(value) AllowValueMatcher.new(value) end
def belong_to(name)
it { should belong_to(:parent) }
Ensure that the belongs_to relationship exists.
def belong_to(name) AssociationMatcher.new(:belongs_to, name) end
def ensure_inclusion_of(attr)
it { should ensure_inclusion_of(:age).in_range(0..100) }
Example:
translation for :inclusion.
errors.on(:attribute). Regexp or string. Defaults to the
* with_high_message - value the test expects to find in
translation for :inclusion.
errors.on(:attribute). Regexp or string. Defaults to the
* with_low_message - value the test expects to find in
* in_range - the range of allowed values for this attribute
Options:
Ensure that the attribute's value is in the range specified
def ensure_inclusion_of(attr) EnsureInclusionOfMatcher.new(attr) end
def ensure_length_of(attr)
is_equal_to(9).
it { should ensure_length_of(:ssn).
with_short_message(/not long enough/) }
is_at_least(3).
it { should ensure_length_of(:name).
is_at_most(20) }
is_at_least(6).
it { should ensure_length_of(:password).
Examples:
is_equal_to.
translation for :wrong_length. Used in conjunction with
errors.on(:attribute). Regexp or string. Defaults to the
* with_message - value the test expects to find in
translation for :too_long.
errors.on(:attribute). Regexp or string. Defaults to the
* with_long_message - value the test expects to find in
translation for :too_short.
errors.on(:attribute). Regexp or string. Defaults to the
* with_short_message - value the test expects to find in
* is_equal_to - exact requred length of this attribute
* is_at_most - maximum length of this attribute
* is_at_least - minimum length of this attribute
Options:
Ensures that the length of the attribute is validated.
def ensure_length_of(attr) EnsureLengthOfMatcher.new(attr) end
def have_and_belong_to_many(name)
it { should have_and_belong_to_many(:posts) }
the join table is in place.
Ensures that the has_and_belongs_to_many relationship exists, and that
def have_and_belong_to_many(name) AssociationMatcher.new(:has_and_belongs_to_many, name) end
def have_db_column(column)
with_options(:precision => 10, :scale => 2) }
of_type(:decimal).
it { should have_db_column(:salary).
it { should_not have_db_column(:admin).of_type(:boolean) }
Examples:
(:default, :null, :limit, :precision, :scale)
* with_options - same options available in migrations
* of_type - db column type (:integer, :string, etc.)
Options:
Ensures the database column exists.
def have_db_column(column) HaveDbColumnMatcher.new(:have_db_column, column) end
def have_index(columns)
it { should have_index(:ssn).unique(true) }
it { should have_index([:commentable_type, :commentable_id]) }
it { should have_index(:age) }
Examples:
unique or not. Default = nil
constraint. Use nil if you don't care whether the index is
constraint. Use false to explicitly test for a non-unique
constraint. Use true to explicitly test for a unique
* unique - whether or not the index has a unique
Options:
columns.
Ensures that there are DB indices on the given columns or tuples of
def have_index(columns) HaveIndexMatcher.new(:have_index, columns) end
def have_many(name)
it { should_have_many(:enemies).dependent(:destroy) }
it { should_have_many(:enemies).through(:friends) }
it { should_have_many(:friends) }
Example:
dependent option.
* dependent - tests that the association makes use of the
* through - association name for has_many :through
Options:
associations.
associated table has the required columns. Works with polymorphic
Ensures that the has_many relationship exists. Will also test that the
def have_many(name) AssociationMatcher.new(:has_many, name) end
def have_named_scope(scope_call)
end
scoped(:limit => c)
def self.recent(c)
Or for
named_scope :recent, lambda {|c| {:limit => c}}
Passes for
it { should have_named_scope('recent(1)').finding(:limit => 1) }
it { should have_named_scope('recent(5)').finding(:limit => 5) }
You can test lambdas or methods that return ActiveRecord#scoped calls:
end
scoped(:conditions => {:visible => true})
def self.visible
Or for
named_scope :visible, :conditions => {:visible => true}
Passes for
finding(:conditions => {:visible => true}) }
it { should have_named_scope(:visible).
Example:
pass on to find.
* in_context - Any of the options that the named scope would
Options:
instance variables that an example would.
which will be evaled. The eval'd method call has access to all the same
scope_call can be either a symbol, or a Ruby expression in a String
NamedScope object with the proxy options set to the options you supply.
Ensures that the model has a method named scope_call that returns a
def have_named_scope(scope_call) HaveNamedScopeMatcher.new(scope_call).in_context(self) end
def have_one(name)
it { should have_one(:god) } # unless hindu
Example:
dependent option.
* :dependent - tests that the association makes use of the
Options:
associations.
associated table has the required columns. Works with polymorphic
Ensure that the has_one relationship exists. Will also test that the
def have_one(name) AssociationMatcher.new(:has_one, name) end
def have_readonly_attribute(value)
it { should have_readonly_attributes(:password) }
created.
Ensures that the attribute cannot be changed once the record has been
def have_readonly_attribute(value) HaveReadonlyAttributeMatcher.new(value) end
def validate_acceptance_of(attr)
it { should validate_acceptance_of(:eula) }
Example:
translation for :accepted.
errors.on(:attribute). Regexp or string. Defaults to the
* with_message - value the test expects to find in
Options:
accepted.
Ensures that the model cannot be saved the given attribute is not
def validate_acceptance_of(attr) ValidateAcceptanceOfMatcher.new(attr) end
def validate_numericality_of(attr)
it { should validate_numericality_of(:age) }
Example:
translation for :not_a_number.
errors.on(:attribute). Regexp or string. Defaults to the
* with_message - value the test expects to find in
Options:
Ensure that the attribute is numeric
def validate_numericality_of(attr) ValidateNumericalityOfMatcher.new(attr) end
def validate_presence_of(attr)
with_message(/is not optional/) }
it { should validate_presence_of(:name).
it { should validate_presence_of(:name) }
Examples:
Defaults to the translation for :blank.
errors.on(:attribute). Regexp or String.
* with_message - value the test expects to find in
Options:
present.
Ensures that the model is not valid if the given attribute is not
def validate_presence_of(attr) ValidatePresenceOfMatcher.new(attr) end
def validate_uniqueness_of(attr)
it { should validate_uniqueness_of(:keyword).case_insensitive }
scoped_to(:first_name, :last_name) }
it { should validate_uniqueness_of(:email).
it { should validate_uniqueness_of(:email).scoped_to(:name) }
it { should validate_uniqueness_of(:keyword).with_message(/dup/) }
it { should validate_uniqueness_of(:keyword) }
Examples:
check case. Off by default. Ignored by non-text attributes.
* case_insensitive - ensures that the validation does not
* scoped_to - field(s) to scope the uniqueness to.
Defaults to the translation for :taken.
errors.on(:attribute). Regexp or String.
* with_message - value the test expects to find in
Options:
end
it { should validate_uniqueness_of(:email) }
before(:each) { User.create!(:email => 'address@example.com') }
describe User do
the model being tested, like so:
so this will always fail if you have not saved at least one record for
Internally, this uses values from existing records to test validations,
Ensures that the model is invalid if the given attribute is not unique.
def validate_uniqueness_of(attr) ValidateUniquenessOfMatcher.new(attr) end