freerange / mocha

A mocking and stubbing library for Ruby
https://mocha.jamesmead.org
Other
1.23k stars 158 forks source link

Fail fast if invocation matches never expectation #679

Open floehopper opened 1 week ago

floehopper commented 1 week ago

TODO

https://github.com/freerange/mocha/blob/f899c034a6f1472788936f2a889ae8d5c323f1de/test/acceptance/expected_invocation_count_test.rb#L202-L214

Previously when an invocation matched an expectation which did not allow invocations (i.e. Expectation#never had been called on it), but the invocation also matched another expectation which did allow invocations, then the test would not fail with an unexpected invocation error.

This was happening because neither the if condition was true, because the "never" expectation was not returned by ExpectationList#match_allowing_invocation, but the other expectation allowing expectations was returned. Thus Expectation#invoke was called on the latter and Mock#raise_unexpected_invocation_error was not called.

This behaviour was confusing and had led to a number of issues being raised over the years: https://github.com/freerange/mocha/issues/44, https://github.com/freerange/mocha/issues/131, https://github.com/freerange/mocha/issues/490 & most recently https://github.com/freerange/mocha/issues/678. Previously I had thought this was a symptom of the JMock v1 dispatch behaviour (which might still be true) and thus would be best addressed by adopting the JMock v2 dispatch behaviour (https://github.com/freerange/mocha/issues/173). However, having considered this specific scenario involving a "never" expectation more carefully, I've decided to try to fix it with the changes in this PR.

Now a test like this will fail with an unexpected invocation error:

mock = mock('mock')
mock.stubs(:method)
mock.expects(:method).never
mock.method

unexpected invocation: #<Mock:mock>.method()
unsatisfied expectations:
- expected never, invoked once: #<Mock:mock>.method(any_parameters)
satisfied expectations:
- allowed any number of times, invoked never: #<Mock:mock>.method(any_parameters)

Closes https://github.com/freerange/mocha/issues/678. Also addresses https://github.com/freerange/mocha/issues/490, https://github.com/freerange/mocha/issues/131 & https://github.com/freerange/mocha/issues/44.