Module: Shoulda::ActiveModel::Macros

Includes:
Matchers
Included in:
Test::Unit::TestCase
Defined in:
lib/shoulda/active_model/macros.rb

Overview

Macro test helpers for your active model models

These helpers will test most of the validations and associations for your ActiveModel 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"
end

For all of these helpers, the last parameter may be a hash of options.

Instance Method Summary collapse

Methods included from Matchers

#allow_value, #ensure_inclusion_of, #ensure_length_of, #validate_acceptance_of, #validate_format_of, #validate_numericality_of, #validate_presence_of, #validate_uniqueness_of

Instance Method Details

#should_allow_values_for(attribute, *good_values) ⇒ Object

Ensures that the attribute can be set to the given values.

Example:

should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"


96
97
98
99
100
101
102
103
104
# File 'lib/shoulda/active_model/macros.rb', line 96

def should_allow_values_for(attribute, *good_values)
  get_options!(good_values)
  good_values.each do |value|
    matcher = allow_value(value).for(attribute)
    should matcher.description do
      assert_accepts matcher, subject
    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

Options:

  • :short_message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.too_short') % min_length

Example:

should_ensure_length_at_least :name, 3


141
142
143
144
145
146
147
148
149
150
151
# File 'lib/shoulda/active_model/macros.rb', line 141

def should_ensure_length_at_least(attribute, min_length, opts = {})
  short_message = get_options!([opts], :short_message)

  matcher = ensure_length_of(attribute).
    is_at_least(min_length).
    with_short_message(short_message)

  should matcher.description do
    assert_accepts matcher, subject
  end
end

#should_ensure_length_in_range(attribute, range, opts = {}) ⇒ Object

Ensures that the length of the attribute is in the given range

Options:

  • :short_message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.too_short') % range.first

  • :long_message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.too_long') % range.last

Example:

should_ensure_length_in_range :password, (6..20)


117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/shoulda/active_model/macros.rb', line 117

def should_ensure_length_in_range(attribute, range, opts = {})
  short_message, long_message = get_options!([opts], 
                                             :short_message,
                                             :long_message)
  matcher = ensure_length_of(attribute).
    is_at_least(range.first).
    with_short_message(short_message).
    is_at_most(range.last).
    with_long_message(long_message)

  should matcher.description do
    assert_accepts matcher, subject
  end
end

#should_ensure_length_is(attribute, length, opts = {}) ⇒ Object

Ensures that the length of the attribute is exactly a certain length

Options:

  • :message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.wrong_length') % length

Example:

should_ensure_length_is :ssn, 9


162
163
164
165
166
167
168
169
170
171
# File 'lib/shoulda/active_model/macros.rb', line 162

def should_ensure_length_is(attribute, length, opts = {})
  message = get_options!([opts], :message)
  matcher = ensure_length_of(attribute).
    is_equal_to(length).
    with_message(message)

  should matcher.description do
    assert_accepts matcher, subject
  end
end

#should_ensure_value_in_range(attribute, range, opts = {}) ⇒ Object

Ensure that the attribute is in the range specified

Options:

  • :low_message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.inclusion')

  • :high_message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.inclusion')

Example:

should_ensure_value_in_range :age, (0..100)


184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/shoulda/active_model/macros.rb', line 184

def should_ensure_value_in_range(attribute, range, opts = {})
  message, low_message, high_message = get_options!([opts],
                                                    :message,
                                                    :low_message,
                                                    :high_message)
  matcher = ensure_inclusion_of(attribute).
    in_range(range).
    with_message(message).
    with_low_message(low_message).
    with_high_message(high_message)
  should matcher.description do
    assert_accepts matcher, subject
  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


223
224
225
226
227
228
229
230
231
# File 'lib/shoulda/active_model/macros.rb', line 223

def should_have_class_methods(*methods)
  get_options!(methods)
  klass = described_type
  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_instance_methods(*methods) ⇒ Object

Ensure that the given instance methods are defined on the model.

should_have_instance_methods :email, :name, :name=


237
238
239
240
241
242
243
244
245
# File 'lib/shoulda/active_model/macros.rb', line 237

def should_have_instance_methods(*methods)
  get_options!(methods)
  klass = described_type
  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_not_allow_values_for(attribute, *bad_values) ⇒ Object

Ensures that the attribute cannot be set to the given values

Options:

  • :message - value the test expects to find in errors.on(:attribute). Regexp or string. If omitted, the test will pass if there is ANY error in errors.on(:attribute).

Example:

should_not_allow_values_for :isbn, "bad 1", "bad 2"


81
82
83
84
85
86
87
88
89
# File 'lib/shoulda/active_model/macros.rb', line 81

def should_not_allow_values_for(attribute, *bad_values)
  message = get_options!(bad_values, :message)
  bad_values.each do |value|
    matcher = allow_value(value).for(attribute).with_message(message)
    should "not #{matcher.description}" do
      assert_rejects matcher, subject
    end
  end
end

#should_validate_acceptance_of(*attributes) ⇒ Object

Ensures that the model cannot be saved if one of the attributes listed is not accepted.

Options:

  • :message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.accepted')

Example:

should_validate_acceptance_of :eula


256
257
258
259
260
261
262
263
264
265
# File 'lib/shoulda/active_model/macros.rb', line 256

def should_validate_acceptance_of(*attributes)
  message = get_options!(attributes, :message)

  attributes.each do |attribute|
    matcher = validate_acceptance_of(attribute).with_message(message)
    should matcher.description do
      assert_accepts matcher, subject
    end
  end
end

#should_validate_numericality_of(*attributes) ⇒ Object

Ensure that the attribute is numeric

Options:

  • :message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.not_a_number')

Example:

should_validate_numericality_of :age


208
209
210
211
212
213
214
215
216
217
# File 'lib/shoulda/active_model/macros.rb', line 208

def should_validate_numericality_of(*attributes)
  message = get_options!(attributes, :message)
  attributes.each do |attribute|
    matcher = validate_numericality_of(attribute).
      with_message(message)
    should matcher.description do
      assert_accepts matcher, subject
    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.

Options:

  • :message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.errors.messages.blank')

Example:

should_validate_presence_of :name, :phone_number


27
28
29
30
31
32
33
34
35
36
# File 'lib/shoulda/active_model/macros.rb', line 27

def should_validate_presence_of(*attributes)
  message = get_options!(attributes, :message)

  attributes.each do |attribute|
    matcher = validate_presence_of(attribute).with_message(message)
    should matcher.description do
      assert_accepts(matcher, subject)
    end
  end
end

#should_validate_uniqueness_of(*attributes) ⇒ Object

  • :message - value the test expects to find in errors.on(:attribute). Regexp or string. Default = I18n.translate('activemodel.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


56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/shoulda/active_model/macros.rb', line 56

def should_validate_uniqueness_of(*attributes)
  message, scope, case_sensitive = get_options!(attributes, :message, :scoped_to, :case_sensitive)
  scope = [*scope].compact
  case_sensitive = true if case_sensitive.nil?

  attributes.each do |attribute|
    matcher = validate_uniqueness_of(attribute).
      with_message(message).scoped_to(scope)
    matcher = matcher.case_insensitive unless case_sensitive
    should matcher.description do
      assert_accepts(matcher, subject)
    end
  end
end