Closed elvetemedve closed 4 years ago
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. :)
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. As mentioned in the PR we could even make the order of errors to be the same as before with a bit more change while still fixing the problem of https://github.com/phpspec/prophecy/issues/120
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 is also another drawback: the stack trace of the UnexpectedCallException will not longer tell you where the unexpected call was done.
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
.