Module: AssertDifference

Defined in:
lib/assert_difference.rb,
lib/assert_difference/version.rb,
lib/assert_difference/expectation.rb

Overview

This is the AssertDifference module, which you should include on your test class to be able to use the #assert_difference method. To use it with Test::Unit add this code:

class Test::Unit::TestCase
  include AssertDifference
end

or in Rails:

class ActiveSupport::TestCase
  # ...
  include AssertDifference
end

and to use it with RSpec:

RSpec.configure do |config|
  config.include AssertDifference
end

Author:

  • José Pablo Fernández

Constant Summary collapse

VERSION =
"1.0.0"

Instance Method Summary collapse

Instance Method Details

#assert_difference(expectations, expected_difference = nil, error_message = nil, &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, :article => {...}
end

An arbitrary expression is passed in and evaluated.

assert_difference "assigns(:article).comments(:reload).size" do
  post :create, :comment => {...}
end

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

assert_difference "Article.count", -1 do
  post :delete, :id => ...
end

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

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

A error message can be specified.

assert_difference "Article.count", -1, "An Article should be destroyed" do
  post :delete, :id => ...
end

Various assertions can be combined into one, instead of writing:

assert_difference "Company.count" do
  assert_difference "User.count", 5 do
    assert_difference "Article.count", -1 do
      post :something
    end
  end
end

you can now write:

assert_difference "Company.count" => 1, "User.count" => 5, "Article.count" => -1 do
  post :something
end

the results of the block is the result of the assert, so you can write:

email = assert_difference "ActionMailer::Base.deliveries.count" => 1 do
    Mailer.reset_password_email(@user).deliver
end
assert_equal [@user.email], email.to

the expectations can also be ranges, for example:

assert_difference "Article.count" => 1, "sample_comments.count" => 2..4 do
  post :something
end

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/assert_difference.rb', line 91

def assert_difference(expectations, expected_difference = nil, error_message = nil, &block)
  binding      = block.send(:binding)
  expectations = Expectation.build_expectations(expectations, expected_difference, binding)

  result = yield

  expectations.map &:eval_after

  failed_expectations = expectations.reject &:passed?
  if failed_expectations.any?
    all_error_messages = failed_expectations.map(&:error_message).join("\n\n").strip
    all_error_messages = "#{error_message}.\n#{all_error_messages}" unless error_message.nil?
    fail all_error_messages
  end

  result
end