Module: Shoulda::Matchers::ActiveModel
- Defined in:
- lib/shoulda/matchers/active_model.rb,
lib/shoulda/matchers/active_model/errors.rb,
lib/shoulda/matchers/active_model/helpers.rb,
lib/shoulda/matchers/active_model/validator.rb,
lib/shoulda/matchers/active_model/qualifiers.rb,
lib/shoulda/matchers/active_model/comparison_matcher.rb,
lib/shoulda/matchers/active_model/validation_matcher.rb,
lib/shoulda/matchers/active_model/allow_value_matcher.rb,
lib/shoulda/matchers/active_model/qualifiers/allow_nil.rb,
lib/shoulda/matchers/active_model/numericality_matchers.rb,
lib/shoulda/matchers/active_model/disallow_value_matcher.rb,
lib/shoulda/matchers/active_model/qualifiers/allow_blank.rb,
lib/shoulda/matchers/active_model/validation_message_finder.rb,
lib/shoulda/matchers/active_model/validate_length_of_matcher.rb,
lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb,
lib/shoulda/matchers/active_model/have_secure_password_matcher.rb,
lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb,
lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb,
lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb,
lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb,
lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb,
lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb,
lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb,
lib/shoulda/matchers/active_model/numericality_matchers/submatchers.rb,
lib/shoulda/matchers/active_model/numericality_matchers/range_matcher.rb,
lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb,
lib/shoulda/matchers/active_model/allow_value_matcher/successful_check.rb,
lib/shoulda/matchers/active_model/validation_matcher/build_description.rb,
lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb,
lib/shoulda/matchers/active_model/allow_value_matcher/successful_setting.rb,
lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb,
lib/shoulda/matchers/active_model/qualifiers/ignore_interference_by_writer.rb,
lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb,
lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb,
lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb,
lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb,
lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb,
lib/shoulda/matchers/active_model/allow_value_matcher/attribute_does_not_exist_error.rb,
lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb,
lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb
Overview
This module provides matchers that are used to test behavior within ActiveModel or ActiveRecord classes.
### Testing conditional validations
If your model defines a validation conditionally – meaning that the validation is declared with an ‘:if` or `:unless` option – how do you test it? You might expect the validation matchers here to have corresponding `if` or `unless` qualifiers, but this isn’t what you use. Instead, before using the matcher in question, you place the record you’re testing in a state such that the validation you’re also testing will be run. A common way to do this is to make a new ‘context` and override the subject to populate the record accordingly. You’ll also want to make sure to test that the validation is not run when the conditional fails.
Here’s an example to illustrate what we mean:
class User
include ActiveModel::Model
attr_accessor :role, :admin
validates_presence_of :role, if: :admin
end
# RSpec
RSpec.describe User, type: :model do
context "when an admin" do
subject { User.new(admin: true) }
it { should validate_presence_of(:role) }
end
context "when not an admin" do
subject { User.new(admin: false) }
it { should_not validate_presence_of(:role) }
end
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
context "when an admin" do
subject { User.new(admin: true) }
should validate_presence_of(:role)
end
context "when not an admin" do
subject { User.new(admin: false) }
should_not validate_presence_of(:role)
end
end
Defined Under Namespace
Modules: Helpers, NumericalityMatchers, Qualifiers Classes: AllowValueMatcher, ComparisonMatcher, CouldNotDetermineValueOutsideOfArray, CouldNotSetPasswordError, DisallowValueMatcher, HaveSecurePasswordMatcher, NonNullableBooleanError, ValidateAbsenceOfMatcher, ValidateAcceptanceOfMatcher, ValidateComparisonOfMatcher, ValidateConfirmationOfMatcher, ValidateExclusionOfMatcher, ValidateInclusionOfMatcher, ValidateLengthOfMatcher, ValidateNumericalityOfMatcher, ValidatePresenceOfMatcher, ValidationMatcher, ValidationMessageFinder, Validator
Instance Method Summary collapse
-
#allow_value(*values) ⇒ AllowValueMatcher
(also: #allow_values)
The ‘allow_value` matcher (or its alias, `allow_values`) is used to ensure that an attribute is valid or invalid if set to one or more values.
-
#have_secure_password(attr = :password) ⇒ HaveSecurePasswordMatcher
The ‘have_secure_password` matcher tests usage of the `has_secure_password` macro.
-
#validate_absence_of(attr) ⇒ ValidateAbsenceOfMatcher
The ‘validate_absence_of` matcher tests the usage of the `validates_absence_of` validation.
-
#validate_acceptance_of(attr) ⇒ ValidateAcceptanceOfMatcher
The ‘validate_acceptance_of` matcher tests usage of the `validates_acceptance_of` validation.
-
#validate_comparison_of(attr) ⇒ ValidateComparisonOfMatcher
The ‘validate_comparison_of` matcher tests usage of the `validates_comparison_of` validation.
-
#validate_confirmation_of(attr) ⇒ ValidateConfirmationOfMatcher
The ‘validate_confirmation_of` matcher tests usage of the `validates_confirmation_of` validation.
-
#validate_exclusion_of(attr) ⇒ ValidateExclusionOfMatcher
The ‘validate_exclusion_of` matcher tests usage of the `validates_exclusion_of` validation, asserting that an attribute cannot take a blocklist of values, and inversely, can take values outside of this list.
-
#validate_inclusion_of(attr) ⇒ ValidateInclusionOfMatcher
The ‘validate_inclusion_of` matcher tests usage of the `validates_inclusion_of` validation, asserting that an attribute can take a allowlist of values and cannot take values outside of this list.
-
#validate_length_of(attr) ⇒ ValidateLengthOfMatcher
The ‘validate_length_of` matcher tests usage of the `validates_length_of` matcher.
-
#validate_numericality_of(attr) ⇒ ValidateNumericalityOfMatcher
The ‘validate_numericality_of` matcher tests usage of the `validates_numericality_of` validation.
-
#validate_presence_of(attr) ⇒ ValidatePresenceOfMatcher
The ‘validate_presence_of` matcher tests usage of the `validates_presence_of` validation.
Instance Method Details
#allow_value(*values) ⇒ AllowValueMatcher Also known as: allow_values
The ‘allow_value` matcher (or its alias, `allow_values`) is used to ensure that an attribute is valid or invalid if set to one or more values.
Take this model for example:
class UserProfile
include ActiveModel::Model
attr_accessor :website_url
validates_format_of :website_url, with: URI.regexp
end
You can use ‘allow_value` to test one value at a time:
# RSpec
RSpec.describe UserProfile, type: :model do
it { should allow_value('https://foo.com').for(:website_url) }
it { should allow_value('https://bar.com').for(:website_url) }
end
# Minitest (Shoulda)
class UserProfileTest < ActiveSupport::TestCase
should allow_value('https://foo.com').for(:website_url)
should allow_value('https://bar.com').for(:website_url)
end
You can also test multiple values in one go, if you like. In the positive sense, this makes an assertion that none of the values cause the record to be invalid. In the negative sense, this makes an assertion that none of the values cause the record to be valid:
# RSpec
RSpec.describe UserProfile, type: :model do
it do
should allow_values('https://foo.com', 'https://bar.com').
for(:website_url)
end
it do
should_not allow_values('foo', 'buz').
for(:website_url)
end
end
# Minitest (Shoulda)
class UserProfileTest < ActiveSupport::TestCase
should allow_values('https://foo.com', 'https://bar.com/baz').
for(:website_url)
should_not allow_values('foo', 'buz').
for(:website_url)
end
#### Caveats
When using ‘allow_value` or any matchers that depend on it, you may encounter an AttributeChangedValueError. This exception is raised if the matcher, in attempting to set a value on the attribute, detects that the value set is different from the value that the attribute returns upon reading it back.
This usually happens if the writer method (‘foo=`, `bar=`, etc.) for that attribute has custom logic to ignore certain incoming values or change them in any way. Here are three examples we’ve seen:
-
You’re attempting to assert that an attribute should not allow nil, yet the attribute’s writer method contains a conditional to do nothing if the attribute is set to nil:
class Foo include ActiveModel::Model attr_reader :bar def (value) return if value.nil? @bar = value end end RSpec.describe Foo, type: :model do it do foo = Foo.new foo. = "baz" # This will raise an AttributeChangedValueError since `foo.bar` is now "123" expect(foo).not_to allow_value(nil).for(:bar) end end
-
You’re attempting to assert that a numeric attribute should not allow a string that contains non-numeric characters, yet the writer method for that attribute strips out non-numeric characters:
class Foo include ActiveModel::Model attr_reader :bar def (value) @bar = value.gsub(/\D+/, '') end end RSpec.describe Foo, type: :model do it do foo = Foo.new # This will raise an AttributeChangedValueError since `foo.bar` is now "123" expect(foo).not_to allow_value("abc123").for(:bar) end end
-
You’re passing a value to ‘allow_value` that the model typecasts into another value:
RSpec.describe Foo, type: :model do # Assume that `attr` is a string # This will raise an AttributeChangedValueError since `attr` typecasts `[]` to `"[]"` it { should_not allow_value([]).for(:attr) } end
Fortunately, if you understand why this is happening, and wish to get around this exception, it is possible to do so. You can use the ‘ignoring_interference_by_writer` qualifier like so:
it do
should_not allow_value([]).
for(:attr).
ignoring_interference_by_writer
end
Please note, however, that this qualifier won’t magically cause your test to pass. It may just so happen that the final value that ends up being set causes the model to fail validation. In that case, you’ll have to figure out what to do. You may need to write your own test, or perhaps even remove your test altogether.
#### Qualifiers
##### on
Use ‘on` if your validation applies only under a certain context.
class UserProfile
include ActiveModel::Model
attr_accessor :birthday_as_string
validates_format_of :birthday_as_string,
with: /^(\d+)-(\d+)-(\d+)$/,
on: :create
end
# RSpec
RSpec.describe UserProfile, type: :model do
it do
should allow_value('2013-01-01').
for(:birthday_as_string).
on(:create)
end
end
# Minitest (Shoulda)
class UserProfileTest < ActiveSupport::TestCase
should allow_value('2013-01-01').
for(:birthday_as_string).
on(:create)
end
##### against
Use ‘against` if the validation is on an attribute other than the attribute being validated:
class UserProfile
include ActiveModel::Model
attr_accessor :website_url
alias_attribute :url, :website_url
validates_format_of :url, with: URI.regexp
end
# RSpec
RSpec.describe UserProfile, type: :model do
it do
should allow_value('https://foo.com').
for(:website_url).
against(:url)
end
end
# Minitest (Shoulda)
class UserProfileTest < ActiveSupport::TestCase
should allow_value('https://foo.com').
for(:website_url).
against(:url)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class UserProfile
include ActiveModel::Model
attr_accessor :state
validates_format_of :state,
with: /^(open|closed)$/,
message: 'State must be open or closed'
end
# RSpec
RSpec.describe UserProfile, type: :model do
it do
should allow_value('open', 'closed').
for(:state).
('State must be open or closed')
end
end
# Minitest (Shoulda)
class UserProfileTest < ActiveSupport::TestCase
should allow_value('open', 'closed').
for(:state).
('State must be open or closed')
end
Use ‘with_message` with a regexp to perform a partial match:
class UserProfile
include ActiveModel::Model
attr_accessor :state
validates_format_of :state,
with: /^(open|closed)$/,
message: 'State must be open or closed'
end
# RSpec
RSpec.describe UserProfile, type: :model do
it do
should allow_value('open', 'closed').
for(:state).
(/open or closed/)
end
end
# Minitest (Shoulda)
class UserProfileTest < ActiveSupport::TestCase
should allow_value('open', 'closed').
for(:state).
(/open or closed/)
end
Use ‘with_message` with the `:against` option if the attribute the validation message is stored under is different from the attribute being validated:
class UserProfile
include ActiveModel::Model
attr_accessor :sports_team
validate :sports_team_must_be_valid
private
def sports_team_must_be_valid
if sports_team !~ /^(Broncos|Titans)$/i
self.errors.add :chosen_sports_team,
'Must be either a Broncos fan or a Titans fan'
end
end
end
# RSpec
RSpec.describe UserProfile, type: :model do
it do
should allow_value('Broncos', 'Titans').
for(:sports_team).
('Must be either a Broncos or Titans fan',
against: :chosen_sports_team
)
end
end
# Minitest (Shoulda)
class UserProfileTest < ActiveSupport::TestCase
should allow_value('Broncos', 'Titans').
for(:sports_team).
('Must be either a Broncos or Titans fan',
against: :chosen_sports_team
)
end
##### ignoring_interference_by_writer
Use ‘ignoring_interference_by_writer` to bypass an AttributeChangedValueError that you have encountered. Please read the Caveats section above for more information.
class Address < ActiveRecord::Base
# Address has a zip_code field which is a string
end
# RSpec
RSpec.describe Address, type: :model do
it do
should_not allow_value([]).
for(:zip_code).
ignoring_interference_by_writer
end
end
# Minitest (Shoulda)
class AddressTest < ActiveSupport::TestCase
should_not allow_value([]).
for(:zip_code).
ignoring_interference_by_writer
end
326 327 328 329 330 331 332 |
# File 'lib/shoulda/matchers/active_model/allow_value_matcher.rb', line 326 def allow_value(*values) if values.empty? raise ArgumentError, 'need at least one argument' else AllowValueMatcher.new(*values) end end |
#have_secure_password(attr = :password) ⇒ HaveSecurePasswordMatcher
The ‘have_secure_password` matcher tests usage of the `has_secure_password` macro.
#### Example
class User
include ActiveModel::Model
include ActiveModel::SecurePassword
attr_accessor :password
attr_accessor :reset_password
has_secure_password
has_secure_password :reset_password
end
# RSpec
RSpec.describe User, type: :model do
it { should have_secure_password }
it { should have_secure_password(:reset_password) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should have_secure_password
should have_secure_password(:reset_password)
end
33 34 35 |
# File 'lib/shoulda/matchers/active_model/have_secure_password_matcher.rb', line 33 def have_secure_password(attr = :password) HaveSecurePasswordMatcher.new(attr) end |
#validate_absence_of(attr) ⇒ ValidateAbsenceOfMatcher
The ‘validate_absence_of` matcher tests the usage of the `validates_absence_of` validation.
class PowerHungryCountry
include ActiveModel::Model
attr_accessor :nuclear_weapons
validates_absence_of :nuclear_weapons
end
# RSpec
RSpec.describe PowerHungryCountry, type: :model do
it { should validate_absence_of(:nuclear_weapons) }
end
# Minitest (Shoulda)
class PowerHungryCountryTest < ActiveSupport::TestCase
should validate_absence_of(:nuclear_weapons)
end
#### Qualifiers
##### on
Use ‘on` if your validation applies only under a certain context.
class PowerHungryCountry
include ActiveModel::Model
attr_accessor :nuclear_weapons
validates_absence_of :nuclear_weapons, on: :create
end
# RSpec
RSpec.describe PowerHungryCountry, type: :model do
it { should validate_absence_of(:nuclear_weapons).on(:create) }
end
# Minitest (Shoulda)
class PowerHungryCountryTest < ActiveSupport::TestCase
should validate_absence_of(:nuclear_weapons).on(:create)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class PowerHungryCountry
include ActiveModel::Model
attr_accessor :nuclear_weapons
validates_absence_of :nuclear_weapons,
message: "there shall be peace on Earth"
end
# RSpec
RSpec.describe PowerHungryCountry, type: :model do
it do
should validate_absence_of(:nuclear_weapons).
("there shall be peace on Earth")
end
end
# Minitest (Shoulda)
class PowerHungryCountryTest < ActiveSupport::TestCase
should validate_absence_of(:nuclear_weapons).
("there shall be peace on Earth")
end
75 76 77 |
# File 'lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb', line 75 def validate_absence_of(attr) ValidateAbsenceOfMatcher.new(attr) end |
#validate_acceptance_of(attr) ⇒ ValidateAcceptanceOfMatcher
The ‘validate_acceptance_of` matcher tests usage of the `validates_acceptance_of` validation.
class Registration
include ActiveModel::Model
attr_accessor :eula
validates_acceptance_of :eula
end
# RSpec
RSpec.describe Registration, type: :model do
it { should validate_acceptance_of(:eula) }
end
# Minitest (Shoulda)
class RegistrationTest < ActiveSupport::TestCase
should validate_acceptance_of(:eula)
end
#### Qualifiers
##### on
Use ‘on` if your validation applies only under a certain context.
class Registration
include ActiveModel::Model
attr_accessor :terms_of_service
validates_acceptance_of :terms_of_service, on: :create
end
# RSpec
RSpec.describe Registration, type: :model do
it do
should validate_acceptance_of(:terms_of_service).
on(:create)
end
end
# Minitest (Shoulda)
class RegistrationTest < ActiveSupport::TestCase
should validate_acceptance_of(:terms_of_service).on(:create)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class Registration
include ActiveModel::Model
attr_accessor :terms_of_service
validates_acceptance_of :terms_of_service,
message: 'You must accept the terms of service'
end
# RSpec
RSpec.describe Registration, type: :model do
it do
should validate_acceptance_of(:terms_of_service).
('You must accept the terms of service')
end
end
# Minitest (Shoulda)
class RegistrationTest < ActiveSupport::TestCase
should validate_acceptance_of(:terms_of_service).
('You must accept the terms of service')
end
78 79 80 |
# File 'lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb', line 78 def validate_acceptance_of(attr) ValidateAcceptanceOfMatcher.new(attr) end |
#validate_comparison_of(attr) ⇒ ValidateComparisonOfMatcher
The ‘validate_comparison_of` matcher tests usage of the `validates_comparison_of` validation.
class Person
include ActiveModel::Model
attr_accessor :gpa
validates_comparison_of :gpa, greater_than: 10
end
# RSpec
RSpec.describe Person, type: :model do
it { should validate_comparison_of(:gpa).is_greater_than(10) }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:gpa).is_greater_than(10)
end
#### Qualifiers
##### on
Use ‘on` if your validation applies only under a certain context.
class Person
include ActiveModel::Model
attribute :number_of_dependents, :integer
attr_accessor :number_of_dependents
validates_comparison_of :number_of_dependents, on: :create, greater_than: 0
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_comparison_of(:number_of_dependents).
is_greater_than(0).
on(:create)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:number_of_dependents).is_greater_than(0).on(:create)
end
##### is_less_than
Use ‘is_less_than` to test usage of the the `:less_than` option. This asserts that the attribute can take a value which is less than the given value and cannot take a value which is greater than or equal to it. It can also accept methods or procs that returns a given value.
class Person
include ActiveModel::Model
attribute :number_of_cars, :integer
attr_accessor :number_of_cars
validates_comparison_of :number_of_cars, less_than: :current_number_of_cars
def current_number_of_cars
10
end
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_comparison_of(:number_of_cars).
is_less_than(:current_number_of_cars)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:number_of_cars).
is_less_than(:current_number_of_cars)
end
##### is_less_than_or_equal_to
Use ‘is_less_than_or_equal_to` to test usage of the `:less_than_or_equal_to` option. This asserts that the attribute can take a value which is less than or equal to the given value and cannot take a value which is greater than it. It can also accept methods or procs that returns a given value.
class Person
include ActiveModel::Model
attr_accessor :birth_date
validates_comparison_of :birth_date, less_than_or_equal_to: Date.new(1987, 12, 31)
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_comparison_of(:birth_date).
is_less_than_or_equal_to(Date.new(1987, 12, 31))
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:birth_date).
is_less_than_or_equal_to(Date.new(1987, 12, 31))
end
##### is_greater_than_or_equal_to
Use ‘is_greater_than_or_equal_to` to test usage of the `:greater_than_or_equal_to` option. This asserts that the attribute can take a value which is greater than or equal to the given value and cannot take a value which is less than it.
class Person
include ActiveModel::Model
attribute :birth_date, :date
attr_accessor :birth_date
validates_comparison_of :birth_date,
greater_than_or_equal_to: -> { 18.years.ago.to_date }
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_comparison_of(:birth_date).
is_greater_than_or_equal_to(-> { 18.years.ago.to_date })
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:birth_date).
is_greater_than_or_equal_to(-> { 18.years.ago.to_date })
end
##### is_greater_than
Use ‘is_greater_than` to test usage of the `:greater_than` option. This asserts that the attribute can take a value which is greater than the given value and cannot take a value less than or equal to it. It can also accept methods or procs that returns a given value.
class Person
include ActiveModel::Model
attribute :legal_age, :integer
attr_accessor :legal_age
validates_comparison_of :legal_age, greater_than: 21
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_comparison_of(:legal_age).
is_greater_than(21)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:legal_age).
is_greater_than(21)
end
##### is_equal_to
Use ‘is_equal_to` to test usage of the `:equal_to` option. This asserts that the attribute can take a value which is equal to the given value and cannot take a value which is not equal. It can also accept methods or procs that returns a given value.
class Person
include ActiveModel::Model
attribute :favorite_color, :string
attr_accessor :favorite_color
validates_comparison_of :favorite_color, equal_to: "blue"
end
# RSpec
RSpec.describe Person, type: :model do
it { should validate_comparison_of(:favorite_color).is_equal_to("blue") }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:favorite_color).is_equal_to("blue")
end
##### is_other_than
Use ‘is_other_than` to test usage of the `:other_than` option. This asserts that the attribute can take a number which is not equal to the given value.
class Person
include ActiveModel::Model
attr_accessor :legal_age
validates_comparison_of :legal_age, other_than: 21
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_comparison_of(:legal_age).
is_other_than(21)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:legal_age).
is_other_than(21)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class Person
include ActiveModel::Model
attr_accessor :number_of_dependents
validates_comparison_of :number_of_dependents, greater_than: 0
message: 'Number of dependents must be a number'
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_comparison_of(:number_of_dependents).
is_greater_than(0).
with_message('Number of dependents must be a number')
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_comparison_of(:number_of_dependents).
is_greater_than(0).
with_message('Number of dependents must be a number')
end
##### allow_nil
Use ‘allow_nil` to assert that the attribute allows nil.
class Post
include ActiveModel::Model
attr_accessor :age
validates_comparison_of :age, greater_than: 0, allow_nil: true
end
# RSpec
RSpec.describe Post, type: :model do
it { should validate_comparison_of(:age).is_greater_than(0).allow_nil }
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_comparison_of(:age).is_greater_than(0).allow_nil
end
277 278 279 |
# File 'lib/shoulda/matchers/active_model/validate_comparison_of_matcher.rb', line 277 def validate_comparison_of(attr) ValidateComparisonOfMatcher.new(attr) end |
#validate_confirmation_of(attr) ⇒ ValidateConfirmationOfMatcher
The ‘validate_confirmation_of` matcher tests usage of the `validates_confirmation_of` validation.
class User
include ActiveModel::Model
attr_accessor :email
validates_confirmation_of :email
end
# RSpec
RSpec.describe User, type: :model do
it { should validate_confirmation_of(:email) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_confirmation_of(:email)
end
#### Qualifiers
##### on
Use ‘on` if your validation applies only under a certain context.
class User
include ActiveModel::Model
attr_accessor :password
validates_confirmation_of :password, on: :create
end
# RSpec
RSpec.describe User, type: :model do
it { should validate_confirmation_of(:password).on(:create) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_confirmation_of(:password).on(:create)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class User
include ActiveModel::Model
attr_accessor :password
validates_confirmation_of :password,
message: 'Please re-enter your password'
end
# RSpec
RSpec.describe User, type: :model do
it do
should validate_confirmation_of(:password).
('Please re-enter your password')
end
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_confirmation_of(:password).
('Please re-enter your password')
end
75 76 77 |
# File 'lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb', line 75 def validate_confirmation_of(attr) ValidateConfirmationOfMatcher.new(attr) end |
#validate_exclusion_of(attr) ⇒ ValidateExclusionOfMatcher
The ‘validate_exclusion_of` matcher tests usage of the `validates_exclusion_of` validation, asserting that an attribute cannot take a blocklist of values, and inversely, can take values outside of this list.
If your blocklist an array of values, use ‘in_array`:
class Game
include ActiveModel::Model
attr_accessor :supported_os
validates_exclusion_of :supported_os, in: ['Mac', 'Linux']
end
# RSpec
RSpec.describe Game, type: :model do
it do
should validate_exclusion_of(:supported_os).
in_array(['Mac', 'Linux'])
end
end
# Minitest (Shoulda)
class GameTest < ActiveSupport::TestCase
should validate_exclusion_of(:supported_os).
in_array(['Mac', 'Linux'])
end
If your blocklist is a range of values, use ‘in_range`:
class Game
include ActiveModel::Model
attr_accessor :floors_with_enemies
validates_exclusion_of :floors_with_enemies, in: 5..8
end
# RSpec
RSpec.describe Game, type: :model do
it do
should validate_exclusion_of(:floors_with_enemies).
in_range(5..8)
end
end
# Minitest (Shoulda)
class GameTest < ActiveSupport::TestCase
should validate_exclusion_of(:floors_with_enemies).
in_range(5..8)
end
#### Qualifiers
##### on
Use ‘on` if your validation applies only under a certain context.
class Game
include ActiveModel::Model
attr_accessor :weapon
validates_exclusion_of :weapon,
in: ['pistol', 'paintball gun', 'stick'],
on: :create
end
# RSpec
RSpec.describe Game, type: :model do
it do
should validate_exclusion_of(:weapon).
in_array(['pistol', 'paintball gun', 'stick']).
on(:create)
end
end
# Minitest (Shoulda)
class GameTest < ActiveSupport::TestCase
should validate_exclusion_of(:weapon).
in_array(['pistol', 'paintball gun', 'stick']).
on(:create)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class Game
include ActiveModel::Model
attr_accessor :weapon
validates_exclusion_of :weapon,
in: ['pistol', 'paintball gun', 'stick'],
message: 'You chose a puny weapon'
end
# RSpec
RSpec.describe Game, type: :model do
it do
should validate_exclusion_of(:weapon).
in_array(['pistol', 'paintball gun', 'stick']).
('You chose a puny weapon')
end
end
# Minitest (Shoulda)
class GameTest < ActiveSupport::TestCase
should validate_exclusion_of(:weapon).
in_array(['pistol', 'paintball gun', 'stick']).
('You chose a puny weapon')
end
117 118 119 |
# File 'lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb', line 117 def validate_exclusion_of(attr) ValidateExclusionOfMatcher.new(attr) end |
#validate_inclusion_of(attr) ⇒ ValidateInclusionOfMatcher
The ‘validate_inclusion_of` matcher tests usage of the `validates_inclusion_of` validation, asserting that an attribute can take a allowlist of values and cannot take values outside of this list.
If your allowlist is an array of values, use ‘in_array`:
class Issue
include ActiveModel::Model
attr_accessor :state
validates_inclusion_of :state,
in: ['open', 'resolved', 'unresolved']
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should validate_inclusion_of(:state).
in_array(['open', 'resolved', 'unresolved'])
end
end
# Minitest (Shoulda)
class IssueTest < ActiveSupport::TestCase
should validate_inclusion_of(:state).
in_array(['open', 'resolved', 'unresolved'])
end
If your allowlist is a range of values, use ‘in_range`:
class Issue
include ActiveModel::Model
attr_accessor :priority
validates_inclusion_of :priority, in: 1..5
end
# RSpec
RSpec.describe Issue, type: :model do
it { should validate_inclusion_of(:priority).in_range(1..5) }
end
# Minitest (Shoulda)
class IssueTest < ActiveSupport::TestCase
should validate_inclusion_of(:priority).in_range(1..5)
end
#### Caveats
We discourage using ‘validate_inclusion_of` with boolean columns. In fact, there is never a case where a boolean column will be anything but true, false, or nil, as ActiveRecord will type-cast an incoming value to one of these three values. That means there isn’t any way we can refute this logic in a test. Hence, this will produce a warning:
it do
should validate_inclusion_of(:imported).
in_array([true, false])
end
The only case where ‘validate_inclusion_of` could be appropriate is for ensuring that a boolean column accepts nil, but we recommend using `allow_value` instead, like this:
it { should allow_value(nil).for(:imported) }
#### Qualifiers
Use ‘on` if your validation applies only under a certain context.
class Issue
include ActiveModel::Model
attr_accessor :severity
validates_inclusion_of :severity,
in: %w(low medium high),
on: :create
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should validate_inclusion_of(:severity).
in_array(%w(low medium high)).
on(:create)
end
end
# Minitest (Shoulda)
class IssueTest < ActiveSupport::TestCase
should validate_inclusion_of(:severity).
in_array(%w(low medium high)).
on(:create)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class Issue
include ActiveModel::Model
attr_accessor :severity
validates_inclusion_of :severity,
in: %w(low medium high),
message: 'Severity must be low, medium, or high'
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should validate_inclusion_of(:severity).
in_array(%w(low medium high)).
('Severity must be low, medium, or high')
end
end
# Minitest (Shoulda)
class IssueTest < ActiveSupport::TestCase
should validate_inclusion_of(:severity).
in_array(%w(low medium high)).
('Severity must be low, medium, or high')
end
##### with_low_message
Use ‘with_low_message` if you have a custom validation message for when a given value is too low.
class Person
include ActiveModel::Model
attr_accessor :age
validate :age_must_be_valid
private
def age_must_be_valid
if age < 65
self.errors.add :age, 'You do not receive any benefits'
end
end
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_inclusion_of(:age).
in_range(0..65).
('You do not receive any benefits')
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_inclusion_of(:age).
in_range(0..65).
('You do not receive any benefits')
end
##### with_high_message
Use ‘with_high_message` if you have a custom validation message for when a given value is too high.
class Person
include ActiveModel::Model
attr_accessor :age
validate :age_must_be_valid
private
def age_must_be_valid
if age > 21
self.errors.add :age, "You're too old for this stuff"
end
end
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_inclusion_of(:age).
in_range(0..21).
("You're too old for this stuff")
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_inclusion_of(:age).
in_range(0..21).
("You're too old for this stuff")
end
##### allow_nil
Use ‘allow_nil` to assert that the attribute allows nil.
class Issue
include ActiveModel::Model
attr_accessor :state
validates_presence_of :state
validates_inclusion_of :state,
in: ['open', 'resolved', 'unresolved'],
allow_nil: true
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should validate_inclusion_of(:state).
in_array(['open', 'resolved', 'unresolved']).
allow_nil
end
end
# Minitest (Shoulda)
class IssueTest < ActiveSupport::TestCase
should validate_inclusion_of(:state).
in_array(['open', 'resolved', 'unresolved']).
allow_nil
end
##### allow_blank
Use ‘allow_blank` to assert that the attribute allows blank.
class Issue
include ActiveModel::Model
attr_accessor :state
validates_presence_of :state
validates_inclusion_of :state,
in: ['open', 'resolved', 'unresolved'],
allow_blank: true
end
# RSpec
RSpec.describe Issue, type: :model do
it do
should validate_inclusion_of(:state).
in_array(['open', 'resolved', 'unresolved']).
allow_blank
end
end
# Minitest (Shoulda)
class IssueTest < ActiveSupport::TestCase
should validate_inclusion_of(:state).
in_array(['open', 'resolved', 'unresolved']).
allow_blank
end
268 269 270 |
# File 'lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb', line 268 def validate_inclusion_of(attr) ValidateInclusionOfMatcher.new(attr) end |
#validate_length_of(attr) ⇒ ValidateLengthOfMatcher
The ‘validate_length_of` matcher tests usage of the `validates_length_of` matcher. Note that this matcher is intended to be used against string columns and associations and not integer columns.
#### Qualifiers
Use ‘on` if your validation applies only under a certain context.
class User
include ActiveModel::Model
attr_accessor :password
validates_length_of :password, minimum: 10, on: :create
end
# RSpec
RSpec.describe User, type: :model do
it do
should validate_length_of(:password).
is_at_least(10).
on(:create)
end
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:password).
is_at_least(10).
on(:create)
end
##### is_at_least
Use ‘is_at_least` to test usage of the `:minimum` option. This asserts that the attribute can take a string which is equal to or longer than the given length and cannot take a string which is shorter. This qualifier also works for associations.
class User
include ActiveModel::Model
attr_accessor :bio
validates_length_of :bio, minimum: 15
end
# RSpec
RSpec.describe User, type: :model do
it { should validate_length_of(:bio).is_at_least(15) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:bio).is_at_least(15)
end
##### is_at_most
Use ‘is_at_most` to test usage of the `:maximum` option. This asserts that the attribute can take a string which is equal to or shorter than the given length and cannot take a string which is longer. This qualifier also works for associations.
class User
include ActiveModel::Model
attr_accessor :status_update
validates_length_of :status_update, maximum: 140
end
# RSpec
RSpec.describe User, type: :model do
it { should validate_length_of(:status_update).is_at_most(140) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:status_update).is_at_most(140)
end
##### is_equal_to
Use ‘is_equal_to` to test usage of the `:is` option. This asserts that the attribute can take a string which is exactly equal to the given length and cannot take a string which is shorter or longer. This qualifier also works for associations.
class User
include ActiveModel::Model
attr_accessor :favorite_superhero
validates_length_of :favorite_superhero, is: 6
end
# RSpec
RSpec.describe User, type: :model do
it { should validate_length_of(:favorite_superhero).is_equal_to(6) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:favorite_superhero).is_equal_to(6)
end
##### is_at_least + is_at_most
Use ‘is_at_least` and `is_at_most` together to test usage of the `:in` option. This qualifies also works for associations.
class User
include ActiveModel::Model
attr_accessor :password
validates_length_of :password, in: 5..30
end
# RSpec
RSpec.describe User, type: :model do
it do
should validate_length_of(:password).
is_at_least(5).is_at_most(30)
end
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:password).
is_at_least(5).is_at_most(30)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class User
include ActiveModel::Model
attr_accessor :password
validates_length_of :password,
minimum: 10,
message: "Password isn't long enough"
end
# RSpec
RSpec.describe User, type: :model do
it do
should validate_length_of(:password).
is_at_least(10).
("Password isn't long enough")
end
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:password).
is_at_least(10).
("Password isn't long enough")
end
##### with_short_message
Use ‘with_short_message` if you are using a custom “too short” message.
class User
include ActiveModel::Model
attr_accessor :secret_key
validates_length_of :secret_key,
in: 15..100,
too_short: 'Secret key must be more than 15 characters'
end
# RSpec
RSpec.describe User, type: :model do
it do
should validate_length_of(:secret_key).
is_at_least(15).
('Secret key must be more than 15 characters')
end
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:secret_key).
is_at_least(15).
('Secret key must be more than 15 characters')
end
##### with_long_message
Use ‘with_long_message` if you are using a custom “too long” message.
class User
include ActiveModel::Model
attr_accessor :secret_key
validates_length_of :secret_key,
in: 15..100,
too_long: 'Secret key must be less than 100 characters'
end
# RSpec
RSpec.describe User, type: :model do
it do
should validate_length_of(:secret_key).
is_at_most(100).
('Secret key must be less than 100 characters')
end
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:secret_key).
is_at_most(100).
('Secret key must be less than 100 characters')
end
##### allow_nil
Use ‘allow_nil` to assert that the attribute allows nil.
class User
include ActiveModel::Model
attr_accessor :bio
validates_length_of :bio, minimum: 15, allow_nil: true
end
# RSpec
describe User do
it { should validate_length_of(:bio).is_at_least(15).allow_nil }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:bio).is_at_least(15).allow_nil
end
##### allow_blank
Use ‘allow_blank` to assert that the attribute allows blank.
class User
include ActiveModel::Model
attr_accessor :bio
validates_length_of :bio, minimum: 15, allow_blank: true
end
# RSpec
describe User do
it { should validate_length_of(:bio).is_at_least(15).allow_blank }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:bio).is_at_least(15).allow_blank
end
##### as_array
Use ‘as_array` if you have an ActiveModel model and the attribute being validated is designed to store an array. (This is not necessary if you have an ActiveRecord model with an array column, as the matcher will detect this automatically.)
class User
include ActiveModel::Model
attribute :arr, array: true
validates_length_of :arr, minimum: 15
end
# RSpec
describe User do
it { should validate_length_of(:arr).as_array.is_at_least(15) }
end
# Minitest (Shoulda)
class UserTest < ActiveSupport::TestCase
should validate_length_of(:arr).as_array.is_at_least(15)
end
289 290 291 |
# File 'lib/shoulda/matchers/active_model/validate_length_of_matcher.rb', line 289 def validate_length_of(attr) ValidateLengthOfMatcher.new(attr) end |
#validate_numericality_of(attr) ⇒ ValidateNumericalityOfMatcher
The ‘validate_numericality_of` matcher tests usage of the `validates_numericality_of` validation.
class Person
include ActiveModel::Model
attr_accessor :gpa
validates_numericality_of :gpa
end
# RSpec
RSpec.describe Person, type: :model do
it { should validate_numericality_of(:gpa) }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:gpa)
end
#### Qualifiers
##### on
Use ‘on` if your validation applies only under a certain context.
class Person
include ActiveModel::Model
attr_accessor :number_of_dependents
validates_numericality_of :number_of_dependents, on: :create
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_numericality_of(:number_of_dependents).
on(:create)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:number_of_dependents).on(:create)
end
##### only_integer
Use ‘only_integer` to test usage of the `:only_integer` option. This asserts that your attribute only allows integer numbers and disallows non-integer ones.
class Person
include ActiveModel::Model
attr_accessor :age
validates_numericality_of :age, only_integer: true
end
# RSpec
RSpec.describe Person, type: :model do
it { should validate_numericality_of(:age).only_integer }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:age).only_integer
end
##### is_less_than
Use ‘is_less_than` to test usage of the the `:less_than` option. This asserts that the attribute can take a number which is less than the given value and cannot take a number which is greater than or equal to it.
class Person
include ActiveModel::Model
attr_accessor :number_of_cars
validates_numericality_of :number_of_cars, less_than: 2
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_numericality_of(:number_of_cars).
is_less_than(2)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:number_of_cars).
is_less_than(2)
end
##### is_less_than_or_equal_to
Use ‘is_less_than_or_equal_to` to test usage of the `:less_than_or_equal_to` option. This asserts that the attribute can take a number which is less than or equal to the given value and cannot take a number which is greater than it.
class Person
include ActiveModel::Model
attr_accessor :birth_year
validates_numericality_of :birth_year, less_than_or_equal_to: 1987
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_numericality_of(:birth_year).
is_less_than_or_equal_to(1987)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:birth_year).
is_less_than_or_equal_to(1987)
end
##### is_equal_to
Use ‘is_equal_to` to test usage of the `:equal_to` option. This asserts that the attribute can take a number which is equal to the given value and cannot take a number which is not equal.
class Person
include ActiveModel::Model
attr_accessor :weight
validates_numericality_of :weight, equal_to: 150
end
# RSpec
RSpec.describe Person, type: :model do
it { should validate_numericality_of(:weight).is_equal_to(150) }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:weight).is_equal_to(150)
end
##### is_greater_than_or_equal_to
Use ‘is_greater_than_or_equal_to` to test usage of the `:greater_than_or_equal_to` option. This asserts that the attribute can take a number which is greater than or equal to the given value and cannot take a number which is less than it.
class Person
include ActiveModel::Model
attr_accessor :height
validates_numericality_of :height, greater_than_or_equal_to: 55
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_numericality_of(:height).
is_greater_than_or_equal_to(55)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:height).
is_greater_than_or_equal_to(55)
end
##### is_greater_than
Use ‘is_greater_than` to test usage of the `:greater_than` option. This asserts that the attribute can take a number which is greater than the given value and cannot take a number less than or equal to it.
class Person
include ActiveModel::Model
attr_accessor :legal_age
validates_numericality_of :legal_age, greater_than: 21
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_numericality_of(:legal_age).
is_greater_than(21)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:legal_age).
is_greater_than(21)
end
##### is_other_than
Use ‘is_other_than` to test usage of the `:other_than` option. This asserts that the attribute can take a number which is not equal to the given value.
class Person
include ActiveModel::Model
attr_accessor :legal_age
validates_numericality_of :legal_age, other_than: 21
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_numericality_of(:legal_age).
is_other_than(21)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:legal_age).
is_other_than(21)
end
##### even
Use ‘even` to test usage of the `:even` option. This asserts that the attribute can take odd numbers and cannot take even ones.
class Person
include ActiveModel::Model
attr_accessor :birth_month
validates_numericality_of :birth_month, even: true
end
# RSpec
RSpec.describe Person, type: :model do
it { should validate_numericality_of(:birth_month).even }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:birth_month).even
end
##### odd
Use ‘odd` to test usage of the `:odd` option. This asserts that the attribute can take a number which is odd and cannot take a number which is even.
class Person
include ActiveModel::Model
attr_accessor :birth_day
validates_numericality_of :birth_day, odd: true
end
# RSpec
RSpec.describe Person, type: :model do
it { should validate_numericality_of(:birth_day).odd }
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:birth_day).odd
end
##### is_in
Use ‘is_in` to test usage of the `:in` option. This asserts that the attribute can take a number which is contained in the given range.
class Person
include ActiveModel::Model
attr_accessor :legal_age
validates_numericality_of :birth_month, in: 1..12
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_numericality_of(:birth_month).
is_in(1..12)
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:birth_month).
is_in(1..12)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class Person
include ActiveModel::Model
attr_accessor :number_of_dependents
validates_numericality_of :number_of_dependents,
message: 'Number of dependents must be a number'
end
# RSpec
RSpec.describe Person, type: :model do
it do
should validate_numericality_of(:number_of_dependents).
('Number of dependents must be a number')
end
end
# Minitest (Shoulda)
class PersonTest < ActiveSupport::TestCase
should validate_numericality_of(:number_of_dependents).
('Number of dependents must be a number')
end
##### allow_nil
Use ‘allow_nil` to assert that the attribute allows nil.
class Post
include ActiveModel::Model
attr_accessor :age
validates_numericality_of :age, allow_nil: true
end
# RSpec
RSpec.describe Post, type: :model do
it { should validate_numericality_of(:age).allow_nil }
end
# Minitest (Shoulda)
class PostTest < ActiveSupport::TestCase
should validate_numericality_of(:age).allow_nil
end
355 356 357 |
# File 'lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb', line 355 def validate_numericality_of(attr) ValidateNumericalityOfMatcher.new(attr) end |
#validate_presence_of(attr) ⇒ ValidatePresenceOfMatcher
The ‘validate_presence_of` matcher tests usage of the `validates_presence_of` validation.
class Robot
include ActiveModel::Model
attr_accessor :arms
validates_presence_of :arms
end
# RSpec
RSpec.describe Robot, type: :model do
it { should validate_presence_of(:arms) }
end
# Minitest (Shoulda)
class RobotTest < ActiveSupport::TestCase
should validate_presence_of(:arms)
end
#### Caveats
Under Rails 4 and greater, if your model ‘has_secure_password` and you are validating presence of the password using a record whose password has already been set prior to calling the matcher, you will be instructed to use a record whose password is empty instead.
For example, given this scenario:
class User < ActiveRecord::Base
has_secure_password validations: false
validates_presence_of :password
end
RSpec.describe User, type: :model do
subject { User.new(password: '123456') }
it { should validate_presence_of(:password) }
end
the above test will raise an error like this:
The validation failed because your User model declares
`has_secure_password`, and `validate_presence_of` was called on a
user which has `password` already set to a value. Please use a user
with an empty `password` instead.
This happens because ‘has_secure_password` itself overrides your model so that it is impossible to set `password` to nil. This means that it is impossible to test that setting `password` to nil places your model in an invalid state (which in turn means that the validation itself is unnecessary).
#### Qualifiers
##### allow_nil
Use ‘allow_nil` if your model has an optional attribute.
class Robot
include ActiveModel::Model
attr_accessor :nickname
validates_presence_of :nickname, allow_nil: true
end
# RSpec
RSpec.describe Robot, type: :model do
it { should validate_presence_of(:nickname).allow_nil }
end
# Minitest (Shoulda)
class RobotTest < ActiveSupport::TestCase
should validate_presence_of(:nickname).allow_nil
end
#### allow_blank
Use ‘allow_blank` to assert that the attribute allows blank.
class Robot
include ActiveModel::Model
attr_accessor :nickname
validates_presence_of :nickname, allow_blank: true
end
# RSpec
RSpec.describe Robot, type: :model do
it { should validate_presence_of(:nickname).allow_blank }
end
# Minitest (Shoulda)
class RobotTest < ActiveSupport::TestCase
should validate_presence_of(:nickname).allow_blank
end
##### on
Use ‘on` if your validation applies only under a certain context.
class Robot
include ActiveModel::Model
attr_accessor :arms
validates_presence_of :arms, on: :create
end
# RSpec
RSpec.describe Robot, type: :model do
it { should validate_presence_of(:arms).on(:create) }
end
# Minitest (Shoulda)
class RobotTest < ActiveSupport::TestCase
should validate_presence_of(:arms).on(:create)
end
##### with_message
Use ‘with_message` if you are using a custom validation message.
class Robot
include ActiveModel::Model
attr_accessor :legs
validates_presence_of :legs, message: 'Robot has no legs'
end
# RSpec
RSpec.describe Robot, type: :model do
it do
should validate_presence_of(:legs).
('Robot has no legs')
end
end
# Minitest (Shoulda)
class RobotTest < ActiveSupport::TestCase
should validate_presence_of(:legs).
('Robot has no legs')
end
150 151 152 |
# File 'lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb', line 150 def validate_presence_of(attr) ValidatePresenceOfMatcher.new(attr) end |