-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Add onlyMethods + addMethods and soft deprecate setMethods #3687
Conversation
Codecov Report
@@ Coverage Diff @@
## master #3687 +/- ##
============================================
+ Coverage 82.38% 82.46% +0.08%
- Complexity 3802 3813 +11
============================================
Files 150 150
Lines 10054 10100 +46
============================================
+ Hits 8283 8329 +46
Misses 1771 1771
Continue to review full report at Codecov.
|
Psalm didn’t find any errors! |
3d94cda
to
e92338d
Compare
The whole point of
Most PHPUnit users, casual or not, should not use the MockBuilder API to begin with but use |
The use case is when you need to mock some methods on a class but not all of them. As far as I know, you can't use createMock for that. I've always used createMock for all dependencies (where you don't need any functionality from the actual class), but for testing actual service classes (that have methods that need to be mocked) where those dependencies are passed in, createMock doesn't seem like an option. So for any use case where you want to test a class but also mock out some methods (in my case, that's generally for mocking public methods on the service and also protected/trait methods that make external calls), from my understanding, you'd use MockBuilder and setMethods for that right now, and I've always seen that in practice in the codebases I've worked on. But the problem I've encountered here is using setMethods makes the test ineffective because there's no check to see if the methods being mocked are real/actually exist in the class. So in a recent case. I saw prod code that was broken because a test was properly mocking data using setMethods and a mock for the method, but the method itself had been removed from the code but was still being called from that service that was being tested. |
You are correct: |
Yeah, that makes sense. It seems for this use case right now there really is no workaround, and in the codebase I work on, in the hundreds of places MockBuilder setMethods/createPartialMock is used, the behavior that was intended was the test would fail if any of the methods that were attempted to be mocked were removed from the code. The only use case we could think of where you wouldn't want that check tied to setMethods is for magic methods maybe, so hence the idea for this new setRealMethods for the majority of standard test cases that can't use createMock and require MockBuiler and some methods mocked but not all. |
I am not happy with the name How about:
|
@sebastianbergmann makes sense, sounds like a solid plan to me. I will try to update this PR later today based on that plan. Thanks! |
3fafd1f
to
a58c6d9
Compare
9c4c1f7
to
f3b6b02
Compare
`MockBuilder::setMethods` is soft deprecated as of PHPUnit 9 So I refactor the test. Please merge laravel#35474 after merging sebastianbergmann/phpunit#3687
`MockBuilder::setMethods` is soft deprecated as of PHPUnit 9 So I refactor the test. Please merge laravel#35474 after merging sebastianbergmann/phpunit#3687
`MockBuilder::setMethods` is soft deprecated as of PHPUnit 9 So I refactor the test. Please merge laravel#35474 after merging sebastianbergmann/phpunit#3687
`MockBuilder::setMethods` is soft deprecated as of PHPUnit 9 So I refactor the test. Please merge #35474 after merging sebastianbergmann/phpunit#3687
All sounds good except case scenario: In this case setMethods would have allowed me to do so, whereas addMethods and onlyMethods will first check the methods against the class I have mocked, which will result in an Class "NonExistentClass" does not exist error. Maybe a check can be added if $this->allowMockingUnknownTypes = true then the ReflectionClass check is bypassed |
Just linking from here to existing documentation change PR, because it seems that current version docs still are missing this stuff: sebastianbergmann/phpunit-documentation-english#205 Ciao :-) |
See: sebastianbergmann/phpunit#3687 Signed-off-by: William Desportes <williamdes@wdes.fr>
Is there an alternative to It's deprecated and links to this issue, but it seems there's no alternative? |
Alternatives were tucked into some of the thoughts on a previous comment here: #3687 (comment)
I would imagine for most use cases, you're looking for |
The purpose of this PR is to provide important testing functionality when using setMethods() on a mock, to which there is currently no workaround to accomplish otherwise (as far as I can see, please correct me if I'm wrong). Right now, any time setMethods is used, the test using it is completely unprotected against any of the methods sent to setMethods not actually existing in the class. In practice, for the large majority of use-cases where setMethods is appropriate, this means that the tests using it are likely not functioning as the test writer expected because the methods in setMethods are not asserted in any way to actually exist, so you can easily just delete methods while refactoring code and have properly written tests still pass with no warning. In practice, this behavior is made even more confusing because so far every developer I've talked to mixes up the strictness of createMock (which tells you when you try to mock a method that didn't exist) with also offering that functionality when you use setMethods, which unfortunately is not the case.
This change provides a simple backwards-compatible way to address this issue, and provide the functionality that most casual PHPUnit users already think they are getting. Anyone who wants the stricter functionality can just search and replace setMethods with the stricter version that asserts the methods actually exist. Also, just to add, the name I added for this new method is kind of just one I came up with quickly - so feedback on that and anything else in this is definitely appreciated.