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_have_valid_fixtures ⇒ Object
Validates that all fixtures of the current class are valid.
-
#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
117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/shoulda/active_record/macros.rb', line 117 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"
201 202 203 204 205 206 207 208 209 210 |
# File 'lib/shoulda/active_record/macros.rb', line 201 def should_allow_values_for(attribute, *good_values) (good_values) 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
424 425 426 427 428 429 430 431 432 433 |
# File 'lib/shoulda/active_record/macros.rb', line 424 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
257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/shoulda/active_record/macros.rb', line 257 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)
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/shoulda/active_record/macros.rb', line 227 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
283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/shoulda/active_record/macros.rb', line 283 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)
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/shoulda/active_record/macros.rb', line 310 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
408 409 410 411 412 413 414 415 416 417 418 |
# File 'lib/shoulda/active_record/macros.rb', line 408 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
439 440 441 442 443 444 445 446 447 |
# File 'lib/shoulda/active_record/macros.rb', line 439 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
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'lib/shoulda/active_record/macros.rb', line 476 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. Usetrueto explicitly test for a unique constraint. Usefalseto explicitly test for a non-unique constraint. Usenilif 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
511 512 513 514 515 516 517 518 519 520 521 |
# File 'lib/shoulda/active_record/macros.rb', line 511 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=
453 454 455 456 457 458 459 460 461 |
# File 'lib/shoulda/active_record/macros.rb', line 453 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
371 372 373 374 375 376 377 378 379 380 |
# File 'lib/shoulda/active_record/macros.rb', line 371 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
592 593 594 595 596 597 598 |
# File 'lib/shoulda/active_record/macros.rb', line 592 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
392 393 394 395 396 397 398 399 400 401 |
# File 'lib/shoulda/active_record/macros.rb', line 392 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
156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/shoulda/active_record/macros.rb', line 156 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_have_valid_fixtures ⇒ Object
Validates that all fixtures of the current class are valid.
Example:
should_have_valid_fixtures
30 31 32 33 34 35 36 37 |
# File 'lib/shoulda/active_record/macros.rb', line 30 def should_have_valid_fixtures klass = model_class should "have valid fixtures" do klass.all.each do |object| assert_valid object 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
133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/shoulda/active_record/macros.rb', line 133 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"
181 182 183 184 185 186 187 188 189 190 |
# File 'lib/shoulda/active_record/macros.rb', line 181 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
352 353 354 355 356 |
# File 'lib/shoulda/active_record/macros.rb', line 352 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
146 147 148 149 150 |
# File 'lib/shoulda/active_record/macros.rb', line 146 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
551 552 553 554 555 |
# File 'lib/shoulda/active_record/macros.rb', line 551 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
65 66 67 68 69 |
# File 'lib/shoulda/active_record/macros.rb', line 65 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
107 108 109 110 111 |
# File 'lib/shoulda/active_record/macros.rb', line 107 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
538 539 540 541 542 543 544 545 546 547 548 |
# File 'lib/shoulda/active_record/macros.rb', line 538 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
339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/shoulda/active_record/macros.rb', line 339 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
52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/shoulda/active_record/macros.rb', line 52 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
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/shoulda/active_record/macros.rb', line 89 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 |