Method: ActiveSupport::Testing::Assertions#assert_changes

Defined in:
activesupport/lib/active_support/testing/assertions.rb

#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 'activesupport/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