Skip to content

Commit

Permalink
Deprecate passing block to mock object constructor
Browse files Browse the repository at this point in the history
This mechanism is confusing, because the block is evaluated in the
context of the newly instantiated block and not in the context of the
current test.

The mechanism is also of dubious value, because it's possible to use
Object#tap or define stubs/expectations with the mock object as the
explicit receiver without the code becoming much more verbose.

It's unfortunate that the deprecations make the tests more complicated,
but we will be able to simplify them again when this functionality is
removed in a later version.

See #286 for further details.
  • Loading branch information
floehopper committed Dec 5, 2016
1 parent 460dce5 commit 5925e04
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 25 deletions.
10 changes: 5 additions & 5 deletions lib/mocha/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def self.included(mod)
#
# @param [String] name identifies mock object in error messages.
# @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {Mock#expects} were called multiple times.
# @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup expectations.
# @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup stubbed methods [deprecated: use Object#tap or define stubs/expectations with an explicit receiver instead].
# @return [Mock] a new mock object
#
# @overload def mock(name, &block)
Expand All @@ -39,7 +39,7 @@ def self.included(mod)
# assert motor.stop
# # an error will be raised unless both Motor#start and Motor#stop have been called
# end
# @example Using the optional block to setup expectations & stubbed methods.
# @example Using the optional block to setup expectations & stubbed methods [deprecated].
# def test_motor_starts_and_stops
# motor = mock('motor') do
# expects(:start).with(100.rpm).returns(true)
Expand All @@ -61,7 +61,7 @@ def mock(*arguments, &block)
#
# @param [String] name identifies mock object in error messages.
# @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
# @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup stubbed methods.
# @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup stubbed methods [deprecated: use Object#tap or define stubs/expectations with an explicit receiver instead].
# @return [Mock] a new mock object
#
# @overload def stub(name, &block)
Expand All @@ -76,7 +76,7 @@ def mock(*arguments, &block)
# # an error will not be raised even if either Motor#start or Motor#stop has not been called
# end
#
# @example Using the optional block to setup expectations & stubbed methods.
# @example Using the optional block to setup expectations & stubbed methods [deprecated].
# def test_motor_starts_and_stops
# motor = stub('motor') do
# expects(:start).with(100.rpm).returns(true)
Expand All @@ -98,7 +98,7 @@ def stub(*arguments, &block)
#
# @param [String] name identifies mock object in error messages.
# @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
# @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup stubbed methods.
# @yield optional block to be evaluated against the mock object instance, giving an alternative way to setup stubbed methods [deprecated: use Object#tap or define stubs/expectations with an explicit receiver instead].
# @return [Mock] a new mock object
#
# @overload def stub_everything(name, &block)
Expand Down
6 changes: 5 additions & 1 deletion lib/mocha/mock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require 'mocha/unexpected_invocation'
require 'mocha/argument_iterator'
require 'mocha/expectation_error_factory'
require 'mocha/deprecation'

module Mocha

Expand Down Expand Up @@ -259,7 +260,10 @@ def initialize(mockery, name = nil, receiver = nil, &block)
@everything_stubbed = false
@responder = nil
@unexpected_invocation = nil
instance_eval(&block) if block
if block
Deprecation.warning('Passing a block is deprecated. Use Object#tap or define stubs/expectations with an explicit receiver instead.')
instance_eval(&block)
end
end

# @private
Expand Down
35 changes: 21 additions & 14 deletions test/acceptance/mock_with_initializer_block_test.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require File.expand_path('../acceptance_test_helper', __FILE__)
require 'mocha/setup'
require 'deprecation_disabler'

class MockWithInitializerBlockTest < Mocha::TestCase

Expand All @@ -15,35 +16,41 @@ def teardown

def test_should_expect_two_method_invocations_and_receive_both_of_them
test_result = run_as_test do
mock = mock() do
expects(:method_1)
expects(:method_2)
DeprecationDisabler.disable_deprecations do
mock = mock() do
expects(:method_1)
expects(:method_2)
end
mock.method_1
mock.method_2
end
mock.method_1
mock.method_2
end
assert_passed(test_result)
end

def test_should_expect_two_method_invocations_but_receive_only_one_of_them
test_result = run_as_test do
mock = mock() do
expects(:method_1)
expects(:method_2)
DeprecationDisabler.disable_deprecations do
mock = mock() do
expects(:method_1)
expects(:method_2)
end
mock.method_1
end
mock.method_1
end
assert_failed(test_result)
end

def test_should_stub_methods
test_result = run_as_test do
mock = mock() do
stubs(:method_1).returns(1)
stubs(:method_2).returns(2)
DeprecationDisabler.disable_deprecations do
mock = mock() do
stubs(:method_1).returns(1)
stubs(:method_2).returns(2)
end
assert_equal 1, mock.method_1
assert_equal 2, mock.method_2
end
assert_equal 1, mock.method_1
assert_equal 2, mock.method_2
end
assert_passed(test_result)
end
Expand Down
1 change: 1 addition & 0 deletions test/deprecation_disabler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ def disable_deprecations
end
end

module_function :disable_deprecations
end
16 changes: 11 additions & 5 deletions test/unit/mockery_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
require 'mocha/mockery'
require 'mocha/state_machine'
require 'mocha/expectation_error_factory'
require 'deprecation_disabler'

class MockeryTest < Mocha::TestCase

include Mocha
include DeprecationDisabler

def test_should_build_instance_of_mockery
mockery = Mockery.instance
Expand All @@ -28,16 +30,20 @@ def test_should_expire_mockery_instance_cache

def test_should_raise_expectation_error_because_not_all_expectations_are_satisfied
mockery = Mockery.new
mock_1 = mockery.named_mock('mock-1') { expects(:method_1) }
mock_2 = mockery.named_mock('mock-2') { expects(:method_2) }
1.times { mock_1.method_1 }
0.times { mock_2.method_2 }
disable_deprecations do
mock_1 = mockery.named_mock('mock-1') { expects(:method_1) }
mock_2 = mockery.named_mock('mock-2') { expects(:method_2) }
1.times { mock_1.method_1 }
0.times { mock_2.method_2 }
end
assert_raises(ExpectationErrorFactory.exception_class) { mockery.verify }
end

def test_should_reset_list_of_mocks_on_teardown
mockery = Mockery.new
mockery.unnamed_mock { expects(:my_method) }
disable_deprecations do
mockery.unnamed_mock { expects(:my_method) }
end
mockery.teardown
assert_nothing_raised(ExpectationErrorFactory.exception_class) { mockery.verify }
end
Expand Down

0 comments on commit 5925e04

Please sign in to comment.