-
Notifications
You must be signed in to change notification settings - Fork 241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix issue #120 by delaying unexpected method call evaluation #441
Fix issue #120 by delaying unexpected method call evaluation #441
Conversation
FYI @ciaranmcnulty We paired with Géza today to attempt to fix this really old issue. Please let us know what you think about it. :) |
2738f61
to
3c22ce0
Compare
3c22ce0
to
5a0903d
Compare
Looks good - is it a BC break though? |
I am not sure... The test result for any existing test should be the same as before, the only difference is the evaluation order of the predictions, which allows to support mocking some methods while only spying others on the same collaborator. |
Test evaluation is not equivalent (see consequences section), but does not break BC. |
Some previously-failing tests will now pass, right? I don't think that's a BC break and I'm pleased to see this contribution :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR caused another BC break (which breaks running the phpspec suite of Propĥecy itself): it now adds method prophecies for shouldNotBeCalled
calls, which can report other calls as unexpected by turning a stub into a mock.
$this->unexpectedCalls->attach(new Call($methodName, $arguments, null, null, $file, $line), $prophecy); | ||
$this->recordedCalls[] = new Call($methodName, $arguments, null, null, $file, $line); | ||
|
||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning null
all the time here means that an unexpected call has a very good chance of triggering a TypeError due to not respecting the return type, instead of being reported as an unexpected call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dunno if already aware of, but wouldn't describing a fallback via Argument::cetera()
do the trick?
See #472 (comment)
There is also another drawback: the stack trace of the UnexpectedCallException will not longer tell you where the unexpected call was done. |
The change in reporting of unexpected calls done in phpspec#441 broke our own spec suite.
The change in reporting of unexpected calls done in phpspec#441 broke our own spec suite.
The change in reporting of unexpected calls done in phpspec#441 broke our own spec suite.
This PR fixes the bug #120.
The problem
Unexpected method call check is happening immediately after the method called on the test subject. This check is not aware of the method prophecies (expected method calls) defined by spies (shouldHaveBeenCalled). Therefor it throws an exception, but it shouldn't.
Given the following specification and implementation, PHPSpec reports an error, but it shouldn't.
Specification
Implementation
Output
The solution
Instead of throwing the exception, the unexpected method calls are recorded, and they are checked again after an example is executed. At this point all spies have registered their method prophecies, so we can identify the correct list of unexpected method calls.
Consequences
The order of reported error types has changed.
Before
After
To make the order unchanged, it would be possible to delay the evaluation of spy predictions in a similar way how it's done with unexpected method calls.
Also currently the "other predictions" check raises an
AggregateException
with all the failed predictions. By delaying spy prediction checks, we could aggregate all failed predictions into oneAggregateException
.