Skip to content

Commit

Permalink
Warning if invocation matches never expectation
Browse files Browse the repository at this point in the history
Currently when an invocation matches an expectation which does not allow
invocations (i.e. `Expectation#never` has been called on it), but the
invocation also matches another expectation which does allow
invocations, then the test does not fail with an unexpected invocation
error.

In #679 I'm planning to change this behaviour so the test fails fast
with an unexpected invocation error. This commit displays a deprecation
warning instead to give users a chance to update their code before the
actual change is made.
  • Loading branch information
floehopper committed Nov 9, 2024
1 parent 05dc3fe commit 094ea8f
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
14 changes: 14 additions & 0 deletions lib/mocha/mock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions test/acceptance/mocked_methods_dispatch_test.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require File.expand_path('../acceptance_test_helper', __FILE__)
require 'deprecation_disabler'
require 'execution_point'

class MockedMethodDispatchTest < Mocha::TestCase
include AcceptanceTest
Expand Down Expand Up @@ -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, #<Mock:mock>.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

0 comments on commit 094ea8f

Please sign in to comment.