Advice request: monkeypatch vs mock.patch
See original GitHub issueI’m working on a codebase where tests use a mixture of mock.patch
and pytest’s monkeypatch
, seemingly based on authors’ personal preferences.
The official docs for the latter, https://docs.pytest.org/en/latest/monkeypatch.html, refer to a blog post that’s nearing its 10th anniversary; meanwhile the earlier made it into Python proper.
I wonder if there’s official advice, like “use X”, or perhaps “if you need feature Y, use Z” to choose between the two.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:52
- Comments:15 (9 by maintainers)
Top Results From Across the Web
What is the difference between mocking and monkey patching?
The mock is the thing that you monkey-patch with to replace the original functionality. The mock library gives you an object you can...
Read more >Monkeypatch vs Mock? : r/learnpython - Reddit
Monkeypatching in pytest is just an implementation of monkey patching, the concept. Mocking is also an implementation of monkey patching, with ...
Read more >Mocks and Monkeypatching in Python - Semaphore Tutorial
This tutorial will help you understand why mocking is important, and show you how to mock in Python with Mock and Pytest monkeypatch....
Read more >How to monkeypatch/mock modules and environments - Pytest
Use monkeypatch.setattr to patch the function or property with your desired ... monkeypatch applies the mock for requests.get with our mock_get function.
Read more >Mocking, Monkey Patching, and Faking Functionality
In our test file, we can “monkey patch” the call to GitHub's API. we can do this using the monkeypatch fixture provided by...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
It does seem to come down to personal preference as far as I’ve seen so far. There’s really three options that work well for pytest (imo) so I’ll outline them here. Note these are my opinions and not necessarily representative of others involved with the project or any sort of “official” stance. It’s possible we should put something together in the documentation since it is a pretty common subject 👍
monkeypatch
MagicMock
, no call tracking, just normal attribute settingmock
(for example, #4536)mock
mock
backportyield
MagicMock
is some crazy magicpytest-mock
: adds amocker
fixture which usesmock
under the hood but with a surface area / api similar tomonkeypatch
mock
, but with the api ofmonkeypatch
. I don’t like using it due to the same reasons I mentioned about scoping of patches inmonkeypatch
In code that I write, I tend to stick to
mock
(if it’s even necessary at all)I also wonder if pytest should gut
monkeypatch
when dropping python2.x and replace the internals withunittest.mock
🤔I’m not @RonnyPfannschmidt but here is my opinion on why
mock.patch
/monkeypatch
is usually better avoided.Monkeypatching, by definition, breaks the abstraction barrier. Some code reaches into some other code and changes it bowls. The code calls
some_function()
, but what actually runs ispatched_in_function()
. The trouble with relying on internal details is that it is brittle. If the code is refactored to callsome_other_function()
instead, the test breaks, even if the behavior is exactly the same.A better alternative is to “formalize” the relationship between the test and the code. The conventional way to do it is give the test explicit control over the particular thing it wants to patch, usually using dependency injection.
For an example I’ll use the post linked by @asottile. In it, they have this code
and they want to write a test for
restart_servers_in_datacenter
, but without it actually going to restart actual servers. What they did was to patch therestart_server
function, and they explain some problems they ran into and how they fixed them.The alternative to patching is do something like this:
Now the test doesn’t need to patch. It can do this:
Now the test cannot make mistakes, it most provide its own implementation of the dependency. It is not possible for the real code to run accidentally. And there is no abstraction being broken, no peace is disturbed, just regular argument passing.
You can decide to fake at a deeper level, if you want to increase the coverage:
Sometimes it’s beneficial to go “full Java” and do this:
depending on the case.
This intersects with general OO good practices for testable code, see here for example. This style of programming is also enforced in the object-capability security model, which I (personally) hope will gain more prominence in the future.
As a disclaimer, I should say that sometimes monkeypatching in tests is necessary, for example when dealing with external code you have no control over. And sometimes it is just easiest and putting more effort is not worth it. And sometimes you intentionally want to test some internal detail. I don’t mean to be dogmatic.