diff options
author | Genadi Samokovarov <gsamokovarov@gmail.com> | 2016-06-13 23:28:05 +0300 |
---|---|---|
committer | Genadi Samokovarov <gsamokovarov@gmail.com> | 2016-07-17 12:58:57 +0300 |
commit | 16f24cd10ffca6be49e394b9404e9564a94aeeda (patch) | |
tree | 97d400eea871ae3f431fe5a0bdd62fe1d5a2fa2b /activesupport/lib/active_support/testing | |
parent | 9fcfb86c42d116cd4145b702dd5c73ce1493b5b9 (diff) | |
download | rails-16f24cd10ffca6be49e394b9404e9564a94aeeda.tar.gz rails-16f24cd10ffca6be49e394b9404e9564a94aeeda.tar.bz2 rails-16f24cd10ffca6be49e394b9404e9564a94aeeda.zip |
Introduce `assert_changes` and `assert_no_changes`
Those are assertions that I really do miss from the standard
`ActiveSupport::TestCase`. Think of those as a more general version of
`assert_difference` and `assert_no_difference` (those can be implemented
by assert_changes, should this change be accepted).
Why do we need those? They are useful when you want to check a
side-effect of an operation. `assert_difference` do cover a really
common case, but we `assert_changes` gives us more control. Having a
global error flag? You can test it easily with `assert_changes`. In
fact, you can be really specific about the initial state and the
terminal one.
```ruby
error = Error.new(:bad)
assert_changes -> { Error.current }, from: nil, to: error do
expected_bad_operation
end
```
`assert_changes` follows `assert_difference` and a string can be given
for evaluation as well.
```ruby
error = Error.new(:bad)
assert_changes 'Error.current', from: nil, to: error do
expected_bad_operation
end
```
Check out the test cases if you wanna see more examples.
:beers:
Diffstat (limited to 'activesupport/lib/active_support/testing')
-rw-r--r-- | activesupport/lib/active_support/testing/assertions.rb | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb index ad83638572..7770aa8006 100644 --- a/activesupport/lib/active_support/testing/assertions.rb +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -1,6 +1,8 @@ module ActiveSupport module Testing module Assertions + UNTRACKED = Object.new # :nodoc: + # Asserts that an expression is not truthy. Passes if <tt>object</tt> is # +nil+ or +false+. "Truthy" means "considered true in a conditional" # like <tt>if foo</tt>. @@ -92,6 +94,93 @@ module ActiveSupport def assert_no_difference(expression, message = nil, &block) assert_difference expression, 0, message, &block end + + # 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 + 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 = yield + + unless from == UNTRACKED + error = "#{expression.inspect} isn't #{from}" + error = "#{message}.\n#{error}" if message + assert from === before, error + end + + after = exp.call + + if to == UNTRACKED + error = "#{expression.inspect} didn't changed" + error = "#{message}.\n#{error}" if message + assert_not_equal before, after, error + else + message = "#{expression.inspect} didn't change to #{to}" + error = "#{message}.\n#{error}" if message + assert to === after, error + end + + retval + end + + # Assertion that the result of evaluating an expression is changed before + # and after invoking the passed in block. + # + # assert_no_changes 'Status.all_good?' 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 + def assert_no_changes(expression, message = nil, &block) + exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) } + + before = exp.call + retval = yield + after = exp.call + + error = "#{expression.inspect} did change to #{after}" + error = "#{message}.\n#{error}" if message + assert_equal before, after, error + + retval + end end end end |