diff --git a/lib/mocha/mock.rb b/lib/mocha/mock.rb index 858e6962..e3a6d9e7 100644 --- a/lib/mocha/mock.rb +++ b/lib/mocha/mock.rb @@ -8,6 +8,7 @@ require 'mocha/parameters_matcher' require 'mocha/argument_iterator' require 'mocha/expectation_error_factory' +require 'mocha/deprecation' module Mocha # Traditional mock object. @@ -323,9 +324,13 @@ def handle_method_call(symbol, arguments, block) invocation = Invocation.new(self, symbol, arguments, block) matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(invocation) + matching_expectation_never_allowing_invocation = all_expectations.match_never_allowing_invocation(invocation) matching_expectation_ignoring_order = all_expectations.match(invocation, ignoring_order: true) if matching_expectation_allowing_invocation + if matching_expectation_never_allowing_invocation + invocation_not_allowed_warning(invocation, matching_expectation_never_allowing_invocation) + end matching_expectation_allowing_invocation.invoke(invocation) elsif matching_expectation_ignoring_order || (!matching_expectation_ignoring_order && !@everything_stubbed) raise_unexpected_invocation_error(invocation, matching_expectation_ignoring_order) @@ -373,6 +378,15 @@ def any_expectations? private + def invocation_not_allowed_warning(invocation, expectation) + messages = [ + "The expectation defined at #{expectation.definition_location} does not allow invocations.", + "However, #{invocation.call_description} was invoked.", + 'This invocation will cause the test to fail fast in a future version of Mocha.' + ] + Deprecation.warning(messages.join(' ')) + end + def raise_unexpected_invocation_error(invocation, matching_expectation) if @unexpected_invocation.nil? @unexpected_invocation = invocation diff --git a/test/acceptance/mocked_methods_dispatch_test.rb b/test/acceptance/mocked_methods_dispatch_test.rb index 9b53aa99..a053661b 100644 --- a/test/acceptance/mocked_methods_dispatch_test.rb +++ b/test/acceptance/mocked_methods_dispatch_test.rb @@ -1,4 +1,6 @@ require File.expand_path('../acceptance_test_helper', __FILE__) +require 'deprecation_disabler' +require 'execution_point' class MockedMethodDispatchTest < Mocha::TestCase include AcceptanceTest @@ -72,4 +74,25 @@ def test_should_find_latest_expectation_with_range_of_expected_invocation_count_ end assert_passed(test_result) end + + def test_should_fail_fast_if_invocation_matches_expectation_with_never_cardinality + execution_point = nil + test_result = run_as_test do + mock = mock('mock') + mock.stubs(:method) + mock.expects(:method).never; execution_point = ExecutionPoint.current + DeprecationDisabler.disable_deprecations do + mock.method + end + end + assert_passed(test_result) + message = Mocha::Deprecation.messages.last + location = execution_point.location + expected = [ + "The expectation defined at #{location} does not allow invocations.", + 'However, #.method() was invoked.', + 'This invocation will cause the test to fail fast in a future version of Mocha.' + ] + assert_equal expected.join(' '), message + end end