Module: Shoulda::ActiveRecord::Macros
- Included in:
- Test::Unit::TestCase
- Defined in:
- lib/shoulda/active_record/macros.rb
Overview
Macro test helpers for your active record models
These helpers will test most of the validations and associations for your ActiveRecord models.
class UserTest < Test::Unit::TestCase
should_validate_presence_of :name, :phone_number
should_not_allow_values_for :phone_number, "abcd", "1234"
should_allow_values_for :phone_number, "(123) 456-7890"
should_not_allow_mass_assignment_of :password
should_have_one :profile
should_have_many :dogs
should_have_many :messes, :through => :dogs
should_belong_to :lover
end
For all of these helpers, the last parameter may be a hash of options.
Instance Method Summary collapse
-
#should_allow_mass_assignment_of(*attributes) ⇒ Object
Ensures that the attribute can be set on mass update.
-
#should_allow_values_for(attribute, *good_values) ⇒ Object
Ensures that the attribute can be set to the given values.
-
#should_belong_to(*associations) ⇒ Object
Ensure that the belongs_to relationship exists.
-
#should_ensure_length_at_least(attribute, min_length, opts = {}) ⇒ Object
Ensures that the length of the attribute is at least a certain length.
-
#should_ensure_length_in_range(attribute, range, opts = {}) ⇒ Object
Ensures that the length of the attribute is in the given range.
-
#should_ensure_length_is(attribute, length, opts = {}) ⇒ Object
Ensures that the length of the attribute is exactly a certain length.
-
#should_ensure_value_in_range(attribute, range, opts = {}) ⇒ Object
Ensure that the attribute is in the range specified.
-
#should_have_and_belong_to_many(*associations) ⇒ Object
Ensures that the has_and_belongs_to_many relationship exists, and that the join table is in place.
-
#should_have_class_methods(*methods) ⇒ Object
Ensure that the given class methods are defined on the model.
-
#should_have_db_columns(*columns) ⇒ Object
(also: #should_have_db_column)
Ensure that the given columns are defined on the models backing SQL table.
-
#should_have_indices(*columns) ⇒ Object
(also: #should_have_index)
Ensures that there are DB indices on the given columns or tuples of columns.
-
#should_have_instance_methods(*methods) ⇒ Object
Ensure that the given instance methods are defined on the model.
-
#should_have_many(*associations) ⇒ Object
Ensures that the has_many relationship exists.
-
#should_have_named_scope(scope_call, find_options = nil) ⇒ Object
Ensures that the model has a method named scope_name that returns a NamedScope object with the proxy options set to the options you supply.
-
#should_have_one(*associations) ⇒ Object
Ensure that the has_one relationship exists.
-
#should_have_readonly_attributes(*attributes) ⇒ Object
Ensures that the attribute cannot be changed once the record has been created.
-
#should_not_allow_mass_assignment_of(*attributes) ⇒ Object
Ensures that the attribute cannot be set on mass update.
-
#should_not_allow_values_for(attribute, *bad_values) ⇒ Object
Ensures that the attribute cannot be set to the given values.
-
#should_only_allow_numeric_values_for(*attributes) ⇒ Object
Deprecated.
-
#should_protect_attributes(*attributes) ⇒ Object
Deprecated.
-
#should_require_acceptance_of(*attributes) ⇒ Object
Deprecated.
-
#should_require_attributes(*attributes) ⇒ Object
Deprecated.
-
#should_require_unique_attributes(*attributes) ⇒ Object
Deprecated.
-
#should_validate_acceptance_of(*attributes) ⇒ Object
Ensures that the model cannot be saved if one of the attributes listed is not accepted.
-
#should_validate_numericality_of(*attributes) ⇒ Object
Ensure that the attribute is numeric.
-
#should_validate_presence_of(*attributes) ⇒ Object
Ensures that the model cannot be saved if one of the attributes listed is not present.
-
#should_validate_uniqueness_of(*attributes) ⇒ Object
-
:message
- value the test expects to find inerrors.on(:attribute)
.
-
Methods included from Matchers
#allow_mass_assignment_of, #allow_value, #belong_to, #ensure_inclusion_of, #ensure_length_of, #have_and_belong_to_many, #have_db_column, #have_index, #have_many, #have_named_scope, #have_one, #have_readonly_attribute, #validate_acceptance_of, #validate_numericality_of, #validate_presence_of, #validate_uniqueness_of
Methods included from Helpers
Instance Method Details
#should_allow_mass_assignment_of(*attributes) ⇒ Object
Ensures that the attribute can be set on mass update.
should_allow_mass_assignment_of :first_name, :last_name
104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/shoulda/active_record/macros.rb', line 104 def should_allow_mass_assignment_of(*attributes) (attributes) klass = model_class attributes.each do |attribute| matcher = allow_mass_assignment_of(attribute) should matcher.description do assert_accepts matcher, klass.new end end end |
#should_allow_values_for(attribute, *good_values) ⇒ Object
Ensures that the attribute can be set to the given values.
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Example:
should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/shoulda/active_record/macros.rb', line 188 def should_allow_values_for(attribute, *good_values) (good_values) klass = model_class klass = model_class good_values.each do |value| matcher = allow_value(value).for(attribute) should matcher.description do assert_accepts matcher, get_instance_of(klass) end end end |
#should_belong_to(*associations) ⇒ Object
Ensure that the belongs_to relationship exists.
should_belong_to :parent
412 413 414 415 416 417 418 419 420 421 |
# File 'lib/shoulda/active_record/macros.rb', line 412 def should_belong_to(*associations) dependent = (associations, :dependent) klass = model_class associations.each do |association| matcher = belong_to(association).dependent(dependent) should matcher.description do assert_accepts(matcher, klass.new) end end end |
#should_ensure_length_at_least(attribute, min_length, opts = {}) ⇒ Object
Ensures that the length of the attribute is at least a certain length
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Options:
-
:short_message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.too_short') % min_length
Example:
should_ensure_length_at_least :name, 3
245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/shoulda/active_record/macros.rb', line 245 def should_ensure_length_at_least(attribute, min_length, opts = {}) = ([opts], :short_message) klass = model_class matcher = ensure_length_of(attribute). is_at_least(min_length). () should matcher.description do assert_accepts matcher, get_instance_of(klass) end end |
#should_ensure_length_in_range(attribute, range, opts = {}) ⇒ Object
Ensures that the length of the attribute is in the given range
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Options:
-
:short_message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.too_short') % range.first
-
:long_message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.too_long') % range.last
Example:
should_ensure_length_in_range :password, (6..20)
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/shoulda/active_record/macros.rb', line 215 def should_ensure_length_in_range(attribute, range, opts = {}) , = ([opts], :short_message, :long_message) klass = model_class matcher = ensure_length_of(attribute). is_at_least(range.first). (). is_at_most(range.last). () should matcher.description do assert_accepts matcher, get_instance_of(klass) end end |
#should_ensure_length_is(attribute, length, opts = {}) ⇒ Object
Ensures that the length of the attribute is exactly a certain length
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Options:
-
:message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.wrong_length') % length
Example:
should_ensure_length_is :ssn, 9
271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/shoulda/active_record/macros.rb', line 271 def should_ensure_length_is(attribute, length, opts = {}) = ([opts], :message) klass = model_class matcher = ensure_length_of(attribute). is_equal_to(length). () should matcher.description do assert_accepts matcher, get_instance_of(klass) end end |
#should_ensure_value_in_range(attribute, range, opts = {}) ⇒ Object
Ensure that the attribute is in the range specified
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Options:
-
:low_message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.inclusion')
-
:high_message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.inclusion')
Example:
should_ensure_value_in_range :age, (0..100)
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/shoulda/active_record/macros.rb', line 298 def should_ensure_value_in_range(attribute, range, opts = {}) , , = ([opts], :message, :low_message, :high_message) klass = model_class matcher = ensure_inclusion_of(attribute). in_range(range). (). (). () should matcher.description do assert_accepts matcher, get_instance_of(klass) end end |
#should_have_and_belong_to_many(*associations) ⇒ Object
Ensures that the has_and_belongs_to_many relationship exists, and that the join table is in place.
should_have_and_belong_to_many :posts, :cars
396 397 398 399 400 401 402 403 404 405 406 |
# File 'lib/shoulda/active_record/macros.rb', line 396 def should_have_and_belong_to_many(*associations) (associations) klass = model_class associations.each do |association| matcher = have_and_belong_to_many(association) should matcher.description do assert_accepts(matcher, klass.new) end end end |
#should_have_class_methods(*methods) ⇒ Object
Ensure that the given class methods are defined on the model.
should_have_class_methods :find, :destroy
427 428 429 430 431 432 433 434 435 |
# File 'lib/shoulda/active_record/macros.rb', line 427 def should_have_class_methods(*methods) (methods) klass = model_class methods.each do |method| should "respond to class method ##{method}" do assert_respond_to klass, method, "#{klass.name} does not have class method #{method}" end end end |
#should_have_db_columns(*columns) ⇒ Object Also known as: should_have_db_column
Ensure that the given columns are defined on the models backing SQL table. Also aliased to should_have_index for readability. Takes the same options available in migrations: :type, :precision, :limit, :default, :null, and :scale
Examples:
should_have_db_columns :id, :email, :name, :created_at
should_have_db_column :email, :type => "string", :limit => 255
should_have_db_column :salary, :decimal, :precision => 15, :scale => 2
should_have_db_column :admin, :default => false, :null => false
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/shoulda/active_record/macros.rb', line 464 def should_have_db_columns(*columns) column_type, precision, limit, default, null, scale, sql_type = (columns, :type, :precision, :limit, :default, :null, :scale, :sql_type) klass = model_class columns.each do |name| matcher = have_db_column(name). of_type(column_type). (:precision => precision, :limit => limit, :default => default, :null => null, :scale => scale, :sql_type => sql_type) should matcher.description do assert_accepts(matcher, klass.new) end end end |
#should_have_indices(*columns) ⇒ Object Also known as: should_have_index
Ensures that there are DB indices on the given columns or tuples of columns. Also aliased to should_have_index for readability
Options:
-
:unique
- whether or not the index has a unique constraint. Usetrue
to explicitly test for a unique constraint. Usefalse
to explicitly test for a non-unique constraint. Usenil
if you don’t care whether the index is unique or not. Default =nil
Examples:
should_have_indices :email, :name, [:commentable_type, :commentable_id]
should_have_index :age
should_have_index :ssn, :unique => true
499 500 501 502 503 504 505 506 507 508 509 |
# File 'lib/shoulda/active_record/macros.rb', line 499 def should_have_indices(*columns) unique = (columns, :unique) klass = model_class columns.each do |column| matcher = have_index(column).unique(unique) should matcher.description do assert_accepts(matcher, klass.new) end end end |
#should_have_instance_methods(*methods) ⇒ Object
Ensure that the given instance methods are defined on the model.
should_have_instance_methods :email, :name, :name=
441 442 443 444 445 446 447 448 449 |
# File 'lib/shoulda/active_record/macros.rb', line 441 def should_have_instance_methods(*methods) (methods) klass = model_class methods.each do |method| should "respond to instance method ##{method}" do assert_respond_to klass.new, method, "#{klass.name} does not have instance method #{method}" end end end |
#should_have_many(*associations) ⇒ Object
Ensures that the has_many relationship exists. Will also test that the associated table has the required columns. Works with polymorphic associations.
Options:
-
:through
- association name forhas_many :through
-
:dependent
- tests that the association makes use of the dependent option.
Example:
should_have_many :friends
should_have_many :enemies, :through => :friends
should_have_many :enemies, :dependent => :destroy
359 360 361 362 363 364 365 366 367 368 |
# File 'lib/shoulda/active_record/macros.rb', line 359 def should_have_many(*associations) through, dependent = (associations, :through, :dependent) klass = model_class associations.each do |association| matcher = have_many(association).through(through).dependent(dependent) should matcher.description do assert_accepts(matcher, klass.new) end end end |
#should_have_named_scope(scope_call, find_options = nil) ⇒ Object
Ensures that the model has a method named scope_name that returns a NamedScope object with the proxy options set to the options you supply. scope_name can be either a symbol, or a method call which will be evaled against the model. The eval’d method call has access to all the same instance variables that a should statement would.
Options: Any of the options that the named scope would pass on to find.
Example:
should_have_named_scope :visible, :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:
should_have_named_scope 'recent(5)', :limit => 5
should_have_named_scope 'recent(1)', :limit => 1
Passes for
named_scope :recent, lambda {|c| {:limit => c}}
Or for
def self.recent(c)
scoped(:limit => c)
end
580 581 582 583 584 585 586 |
# File 'lib/shoulda/active_record/macros.rb', line 580 def should_have_named_scope(scope_call, = nil) klass = model_class matcher = have_named_scope(scope_call).finding() should matcher.description do assert_accepts matcher.in_context(self), klass.new end end |
#should_have_one(*associations) ⇒ Object
Ensure that the has_one relationship exists. Will also test that the associated table has the required columns. Works with polymorphic associations.
Options:
-
:dependent
- tests that the association makes use of the dependent option.
Example:
should_have_one :god # unless hindu
380 381 382 383 384 385 386 387 388 389 |
# File 'lib/shoulda/active_record/macros.rb', line 380 def should_have_one(*associations) dependent = (associations, :dependent) klass = model_class associations.each do |association| matcher = have_one(association).dependent(dependent) should matcher.description do assert_accepts(matcher, klass.new) end end end |
#should_have_readonly_attributes(*attributes) ⇒ Object
Ensures that the attribute cannot be changed once the record has been created.
should_have_readonly_attributes :password, :admin_flag
143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/shoulda/active_record/macros.rb', line 143 def should_have_readonly_attributes(*attributes) (attributes) klass = model_class attributes.each do |attribute| matcher = have_readonly_attribute(attribute) should matcher.description do assert_accepts matcher, klass.new end end end |
#should_not_allow_mass_assignment_of(*attributes) ⇒ Object
Ensures that the attribute cannot be set on mass update.
should_not_allow_mass_assignment_of :password, :admin_flag
120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/shoulda/active_record/macros.rb', line 120 def should_not_allow_mass_assignment_of(*attributes) (attributes) klass = model_class attributes.each do |attribute| matcher = allow_mass_assignment_of(attribute) should "not #{matcher.description}" do assert_rejects matcher, klass.new end end end |
#should_not_allow_values_for(attribute, *bad_values) ⇒ Object
Ensures that the attribute cannot be set to the given values
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Options:
-
:message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.invalid')
Example:
should_not_allow_values_for :isbn, "bad 1", "bad 2"
168 169 170 171 172 173 174 175 176 177 |
# File 'lib/shoulda/active_record/macros.rb', line 168 def should_not_allow_values_for(attribute, *bad_values) = (bad_values, :message) klass = model_class bad_values.each do |value| matcher = allow_value(value).for(attribute).() should "not #{matcher.description}" do assert_rejects matcher, get_instance_of(klass) end end end |
#should_only_allow_numeric_values_for(*attributes) ⇒ Object
Deprecated. See should_validate_numericality_of
340 341 342 343 344 |
# File 'lib/shoulda/active_record/macros.rb', line 340 def should_only_allow_numeric_values_for(*attributes) warn "[DEPRECATION] should_only_allow_numeric_values_for is " << "deprecated. Use should_validate_numericality_of instead." should_validate_numericality_of(*attributes) end |
#should_protect_attributes(*attributes) ⇒ Object
Deprecated. See should_not_allow_mass_assignment_of
133 134 135 136 137 |
# File 'lib/shoulda/active_record/macros.rb', line 133 def should_protect_attributes(*attributes) warn "[DEPRECATION] should_protect_attributes is deprecated. " << "Use should_not_allow_mass_assignment_of instead." should_not_allow_mass_assignment_of(*attributes) end |
#should_require_acceptance_of(*attributes) ⇒ Object
Deprecated. See should_validate_uniqueness_of
539 540 541 542 543 |
# File 'lib/shoulda/active_record/macros.rb', line 539 def should_require_acceptance_of(*attributes) warn "[DEPRECATION] should_require_acceptance_of is deprecated. " << "Use should_validate_acceptance_of instead." should_validate_acceptance_of(*attributes) end |
#should_require_attributes(*attributes) ⇒ Object
Deprecated. See should_validate_presence_of
52 53 54 55 56 |
# File 'lib/shoulda/active_record/macros.rb', line 52 def should_require_attributes(*attributes) warn "[DEPRECATION] should_require_attributes is deprecated. " << "Use should_validate_presence_of instead." should_validate_presence_of(*attributes) end |
#should_require_unique_attributes(*attributes) ⇒ Object
Deprecated. See should_validate_uniqueness_of
94 95 96 97 98 |
# File 'lib/shoulda/active_record/macros.rb', line 94 def should_require_unique_attributes(*attributes) warn "[DEPRECATION] should_require_unique_attributes is deprecated. " << "Use should_validate_uniqueness_of instead." should_validate_uniqueness_of(*attributes) end |
#should_validate_acceptance_of(*attributes) ⇒ Object
Ensures that the model cannot be saved if one of the attributes listed is not accepted.
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Options:
-
:message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.accepted')
Example:
should_validate_acceptance_of :eula
526 527 528 529 530 531 532 533 534 535 536 |
# File 'lib/shoulda/active_record/macros.rb', line 526 def should_validate_acceptance_of(*attributes) = (attributes, :message) klass = model_class attributes.each do |attribute| matcher = validate_acceptance_of(attribute).() should matcher.description do assert_accepts matcher, get_instance_of(klass) end end end |
#should_validate_numericality_of(*attributes) ⇒ Object
Ensure that the attribute is numeric
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Options:
-
:message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.not_a_number')
Example:
should_validate_numericality_of :age
327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/shoulda/active_record/macros.rb', line 327 def should_validate_numericality_of(*attributes) = (attributes, :message) klass = model_class attributes.each do |attribute| matcher = validate_numericality_of(attribute). () should matcher.description do assert_accepts matcher, get_instance_of(klass) end end end |
#should_validate_presence_of(*attributes) ⇒ Object
Ensures that the model cannot be saved if one of the attributes listed is not present.
If an instance variable has been created in the setup named after the model being tested, then this method will use that. Otherwise, it will create a new instance to test against.
Options:
-
:message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.blank')
Example:
should_validate_presence_of :name, :phone_number
39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/shoulda/active_record/macros.rb', line 39 def should_validate_presence_of(*attributes) = (attributes, :message) klass = model_class attributes.each do |attribute| matcher = validate_presence_of(attribute).() should matcher.description do assert_accepts(matcher, get_instance_of(klass)) end end end |
#should_validate_uniqueness_of(*attributes) ⇒ Object
-
:message
- value the test expects to find inerrors.on(:attribute)
. Regexp or string. Default =I18n.translate('activerecord.errors.messages.taken')
-
:scoped_to
- field(s) to scope the uniqueness to. -
:case_sensitive
- whether or not uniqueness is defined by an exact match. Ignored by non-text attributes. Default =true
Examples:
should_validate_uniqueness_of :keyword, :username
should_validate_uniqueness_of :name, :message => "O NOES! SOMEONE STOELED YER NAME!"
should_validate_uniqueness_of :email, :scoped_to => :name
should_validate_uniqueness_of :address, :scoped_to => [:first_name, :last_name]
should_validate_uniqueness_of :email, :case_sensitive => false
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/shoulda/active_record/macros.rb', line 76 def should_validate_uniqueness_of(*attributes) , scope, case_sensitive = (attributes, :message, :scoped_to, :case_sensitive) scope = [*scope].compact case_sensitive = true if case_sensitive.nil? klass = model_class attributes.each do |attribute| matcher = validate_uniqueness_of(attribute). ().scoped_to(scope) matcher = matcher.case_insensitive unless case_sensitive should matcher.description do assert_accepts(matcher, get_instance_of(klass)) end end end |