Module: ActiveSupport::Testing::Assertions

Included in:
ActiveSupport::TestCase
Defined in:
lib/active_support/testing/assertions.rb

Constant Summary collapse

UNTRACKED =

:nodoc:

Object.new

Instance Method Summary collapse

Instance Method Details

#assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block) ⇒ Object

Assertion that the result of evaluating an expression is changed before and after invoking the passed in block.

assert_changes 'Status.all_good?' do
  post :create, params: { status: { ok: false } }
end

You can pass the block as a string to be evaluated in the context of the block. A lambda can be passed for the block as well.

assert_changes -> { Status.all_good? } do
  post :create, params: { status: { ok: false } }
end

The assertion is useful to test side effects. The passed block can be anything that can be converted to string with #to_s.

assert_changes :@object do
  @object = 42
end

The keyword arguments :from and :to can be given to specify the expected initial value and the expected value after the block was executed.

assert_changes :@object, from: nil, to: :foo do
  @object = :foo
end

An error message can be specified.

assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do
  post :create, params: { status: { incident: true } }
end


195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/active_support/testing/assertions.rb', line 195

def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block)
  exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }

  before = exp.call
  retval = _assert_nothing_raised_or_warn("assert_changes", &block)

  unless from == UNTRACKED
    rich_message = -> do
      error = "Expected change from #{from.inspect}, got #{before.inspect}"
      error = "#{message}.\n#{error}" if message
      error
    end
    assert from === before, rich_message
  end

  after = exp.call

  rich_message = -> do
    code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
    error = "`#{code_string}` didn't change"
    error = "#{error}. It was already #{to.inspect}" if before == to
    error = "#{message}.\n#{error}" if message
    error
  end
  refute_equal before, after, rich_message

  unless to == UNTRACKED
    rich_message = -> do
      error = "Expected change to #{to.inspect}, got #{after.inspect}\n"
      error = "#{message}.\n#{error}" if message
      error
    end
    assert to === after, rich_message
  end

  retval
end

#assert_difference(expression, *args, &block) ⇒ Object

Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.

assert_difference 'Article.count' do
  post :create, params: { article: {...} }
end

An arbitrary expression is passed in and evaluated.

assert_difference 'Article.last.comments(:reload).size' do
  post :create, params: { comment: {...} }
end

An arbitrary positive or negative difference can be specified. The default is 1.

assert_difference 'Article.count', -1 do
  post :delete, params: { id: ... }
end

An array of expressions can also be passed in and evaluated.

assert_difference [ 'Article.count', 'Post.count' ], 2 do
  post :create, params: { article: {...} }
end

A hash of expressions/numeric differences can also be passed in and evaluated.

assert_difference ->{ Article.count } => 1, ->{ Notification.count } => 2 do
  post :create, params: { article: {...} }
end

A lambda or a list of lambdas can be passed in and evaluated:

assert_difference ->{ Article.count }, 2 do
  post :create, params: { article: {...} }
end

assert_difference [->{ Article.count }, ->{ Post.count }], 2 do
  post :create, params: { article: {...} }
end

An error message can be specified.

assert_difference 'Article.count', -1, 'An Article should be destroyed' do
  post :delete, params: { id: ... }
end


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/active_support/testing/assertions.rb', line 101

def assert_difference(expression, *args, &block)
  expressions =
    if expression.is_a?(Hash)
      message = args[0]
      expression
    else
      difference = args[0] || 1
      message = args[1]
      Array(expression).index_with(difference)
    end

  exps = expressions.keys.map { |e|
    e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
  }
  before = exps.map(&:call)

  retval = _assert_nothing_raised_or_warn("assert_difference", &block)

  expressions.zip(exps, before) do |(code, diff), exp, before_value|
    actual = exp.call
    rich_message = -> do
      code_string = code.respond_to?(:call) ? _callable_to_source_string(code) : code
      error = "`#{code_string}` didn't change by #{diff}, but by #{actual - before_value}"
      error = "#{message}.\n#{error}" if message
      error
    end
    assert_equal(before_value + diff, actual, rich_message)
  end

  retval
end

#assert_no_changes(expression, message = nil, from: UNTRACKED, &block) ⇒ Object

Assertion that the result of evaluating an expression is not changed before and after invoking the passed in block.

assert_no_changes 'Status.all_good?' do
  post :create, params: { status: { ok: true } }
end

Provide the optional keyword argument :from to specify the expected initial value.

assert_no_changes -> { Status.all_good? }, from: true do
  post :create, params: { status: { ok: true } }
end

An error message can be specified.

assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
  post :create, params: { status: { ok: false } }
end


252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/active_support/testing/assertions.rb', line 252

def assert_no_changes(expression, message = nil, from: UNTRACKED, &block)
  exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }

  before = exp.call
  retval = _assert_nothing_raised_or_warn("assert_no_changes", &block)

  unless from == UNTRACKED
    rich_message = -> do
      error = "Expected initial value of #{from.inspect}, got #{before.inspect}"
      error = "#{message}.\n#{error}" if message
      error
    end
    assert from === before, rich_message
  end

  after = exp.call

  rich_message = -> do
    code_string = expression.respond_to?(:call) ? _callable_to_source_string(expression) : expression
    error = "`#{code_string}` changed"
    error = "#{message}.\n#{error}" if message
    error
  end

  if before.nil?
    assert_nil after, rich_message
  else
    assert_equal before, after, rich_message
  end

  retval
end

#assert_no_difference(expression, message = nil, &block) ⇒ Object

Assertion that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.

assert_no_difference 'Article.count' do
  post :create, params: { article: invalid_attributes }
end

A lambda can be passed in and evaluated.

assert_no_difference -> { Article.count } do
  post :create, params: { article: invalid_attributes }
end

An error message can be specified.

assert_no_difference 'Article.count', 'An Article should not be created' do
  post :create, params: { article: invalid_attributes }
end

An array of expressions can also be passed in and evaluated.

assert_no_difference [ 'Article.count', -> { Post.count } ] do
  post :create, params: { article: invalid_attributes }
end


157
158
159
# File 'lib/active_support/testing/assertions.rb', line 157

def assert_no_difference(expression, message = nil, &block)
  assert_difference expression, 0, message, &block
end

#assert_not(object, message = nil) ⇒ Object

Asserts that an expression is not truthy. Passes if object is nil or false. “Truthy” means “considered true in a conditional” like if foo.

assert_not nil    # => true
assert_not false  # => true
assert_not 'foo'  # => Expected "foo" to be nil or false

An error message can be specified.

assert_not foo, 'foo should be false'


21
22
23
24
# File 'lib/active_support/testing/assertions.rb', line 21

def assert_not(object, message = nil)
  message ||= -> { "Expected #{mu_pp(object)} to be nil or false" }
  assert !object, message
end

#assert_nothing_raisedObject

Assertion that the block should not raise an exception.

Passes if evaluated code in the yielded block raises no exception.

assert_nothing_raised do
  perform_service(param: 'no_exception')
end


48
49
50
51
52
# File 'lib/active_support/testing/assertions.rb', line 48

def assert_nothing_raised
  yield.tap { assert(true) }
rescue => error
  raise Minitest::UnexpectedError.new(error)
end

#assert_raises(*exp, match: nil, &block) ⇒ Object Also known as: assert_raise

Asserts that a block raises one of exp. This is an enhancement of the standard Minitest assertion method with the ability to test error messages.

assert_raises(ArgumentError, match: /incorrect param/i) do
  perform_service(param: 'exception')
end


34
35
36
37
38
# File 'lib/active_support/testing/assertions.rb', line 34

def assert_raises(*exp, match: nil, &block)
  error = super(*exp, &block)
  assert_match(match, error.message) if match
  error
end