These matchers will test most of the validations and associations for your ActiveRecord models.
describe User do it { should validate_presence_of(:name) } it { should validate_presence_of(:phone_number) } %w(abcd 1234).each do |value| it { should_not allow_value(value).for(:phone_number) } end it { should allow_value("(123) 456-7890").for(:phone_number) } it { should_not allow_mass_assignment_of(:password) } it { should have_one(:profile) } it { should have_many(:dogs) } it { should have_many(:messes).through(:dogs) } it { should belong_to(:lover) } end
Ensures that the attribute can be set on mass update.
it { should_not allow_mass_assignment_of(:password) } it { should allow_mass_assignment_of(:first_name) }
# File lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb, line 10 10: def allow_mass_assignment_of(value) 11: AllowMassAssignmentOfMatcher.new(value) 12: end
Ensures that the attribute can be set to the given value.
Options:
Example:
it { should_not allow_value('bad').for(:isbn) } it { should allow_value("isbn 1 2345 6789 0").for(:isbn) }
# File lib/shoulda/active_record/matchers/allow_value_matcher.rb, line 16 16: def allow_value(value) 17: AllowValueMatcher.new(value) 18: end
Ensure that the belongs_to relationship exists.
it { should belong_to(:parent) }
# File lib/shoulda/active_record/matchers/association_matcher.rb, line 9 9: def belong_to(name) 10: AssociationMatcher.new(:belongs_to, name) 11: end
Ensure that the attribute‘s value is in the range specified
Options:
Example:
it { should ensure_inclusion_of(:age).in_range(0..100) }
# File lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb, line 19 19: def ensure_inclusion_of(attr) 20: EnsureInclusionOfMatcher.new(attr) 21: end
Ensures that the length of the attribute is validated.
Options:
Examples:
it { should ensure_length_of(:password). is_at_least(6). is_at_most(20) } it { should ensure_length_of(:name). is_at_least(3). with_short_message(/not long enough/) } it { should ensure_length_of(:ssn). is_equal_to(9). with_message(/is invalid/) }
# File lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb, line 32 32: def ensure_length_of(attr) 33: EnsureLengthOfMatcher.new(attr) 34: end
Ensures that the has_and_belongs_to_many relationship exists, and that the join table is in place.
it { should have_and_belong_to_many(:posts) }
# File lib/shoulda/active_record/matchers/association_matcher.rb, line 51 51: def have_and_belong_to_many(name) 52: AssociationMatcher.new(:has_and_belongs_to_many, name) 53: end
Ensures the database column exists.
Options:
Examples:
it { should_not have_db_column(:admin).of_type(:boolean) } it { should have_db_column(:salary). of_type(:decimal). with_options(:precision => 10, :scale => 2) }
# File lib/shoulda/active_record/matchers/have_db_column_matcher.rb, line 18 18: def have_db_column(column) 19: HaveDbColumnMatcher.new(:have_db_column, column) 20: end
Ensures that there are DB indices on the given columns or tuples of columns.
Options:
Examples:
it { should have_db_index(:age) } it { should have_db_index([:commentable_type, :commentable_id]) } it { should have_db_index(:ssn).unique(true) }
# File lib/shoulda/active_record/matchers/have_db_index_matcher.rb, line 21 21: def have_db_index(columns) 22: HaveDbIndexMatcher.new(:have_index, columns) 23: end
Ensures that the has_many relationship exists. Will also test that the associated table has the required columns. Works with polymorphic associations.
Options:
Example:
it { should_have_many(:friends) } it { should_have_many(:enemies).through(:friends) } it { should_have_many(:enemies).dependent(:destroy) }
# File lib/shoulda/active_record/matchers/association_matcher.rb, line 27 27: def have_many(name) 28: AssociationMatcher.new(:has_many, name) 29: end
Deprecated.
Ensures that the model has a method named scope_call that returns a NamedScope object with the proxy options set to the options you supply. scope_call can be either a symbol, or a Ruby expression in a String which will be evaled. The eval‘d method call has access to all the same instance variables that an example would.
Options:
* <tt>in_context</tt> - Any of the options that the named scope would pass on to find.
Example:
it { should have_named_scope(:visible). finding(:conditions => {:visible => true}) }
Passes for
named_scope :visible, :conditions => {:visible => true}
Or for
def self.visible scoped(:conditions => {:visible => true}) end
You can test lambdas or methods that return ActiveRecord#scoped calls:
it { should have_named_scope('recent(5)').finding(:limit => 5) } it { should have_named_scope('recent(1)').finding(:limit => 1) }
Passes for
named_scope :recent, lambda {|c| {:limit => c}}
Or for
def self.recent(c) scoped(:limit => c) end
# File lib/shoulda/active_record/matchers/have_named_scope_matcher.rb, line 47 47: def have_named_scope(scope_call) 48: warn "[DEPRECATION] should_have_named_scope is deprecated." 49: HaveNamedScopeMatcher.new(scope_call).in_context(self) 50: end
Ensure that the has_one relationship exists. Will also test that the associated table has the required columns. Works with polymorphic associations.
Options:
Example:
it { should have_one(:god) } # unless hindu
# File lib/shoulda/active_record/matchers/association_matcher.rb, line 42 42: def have_one(name) 43: AssociationMatcher.new(:has_one, name) 44: end
Ensures that the attribute cannot be changed once the record has been created.
it { should have_readonly_attributes(:password) }
# File lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb, line 10 10: def have_readonly_attribute(value) 11: HaveReadonlyAttributeMatcher.new(value) 12: end
Ensures that the model cannot be saved the given attribute is not accepted.
Options:
Example:
it { should validate_acceptance_of(:eula) }
# File lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb, line 16 16: def validate_acceptance_of(attr) 17: ValidateAcceptanceOfMatcher.new(attr) 18: end
Ensures that the model is not valid if the given attribute is not formatted correctly.
Options:
Examples:
it { should validate_format_of(:name). with('12345'). with_message(/is not optional/) } it { should validate_format_of(:name). not_with('12D45'). with_message(/is not optional/) }
# File lib/shoulda/active_record/matchers/validate_format_of_matcher.rb, line 23 23: def validate_format_of(attr) 24: ValidateFormatOfMatcher.new(attr) 25: end
Ensure that the attribute is numeric
Options:
Example:
it { should validate_numericality_of(:age) }
# File lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb, line 15 15: def validate_numericality_of(attr) 16: ValidateNumericalityOfMatcher.new(attr) 17: end
Ensures that the model is not valid if the given attribute is not present.
Options:
Examples:
it { should validate_presence_of(:name) } it { should validate_presence_of(:name). with_message(/is not optional/) }
# File lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb, line 18 18: def validate_presence_of(attr) 19: ValidatePresenceOfMatcher.new(attr) 20: end
Ensures that the model is invalid if the given attribute is not unique.
Internally, this uses values from existing records to test validations, so this will always fail if you have not saved at least one record for the model being tested, like so:
describe User do before(:each) { User.create!(:email => 'address@example.com') } it { should validate_uniqueness_of(:email) } end
Options:
Examples:
it { should validate_uniqueness_of(:keyword) } it { should validate_uniqueness_of(:keyword).with_message(/dup/) } it { should validate_uniqueness_of(:email).scoped_to(:name) } it { should validate_uniqueness_of(:email). scoped_to(:first_name, :last_name) } it { should validate_uniqueness_of(:keyword).case_insensitive }
# File lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb, line 33 33: def validate_uniqueness_of(attr) 34: ValidateUniquenessOfMatcher.new(attr) 35: end