In conftest (in an autouse fixture):
monkeypatch.setattr('collector.util.download_data', lambda url:"Winning" )
In collector/util.py:
def download_data(url):
assert False
In the_caller.py:
from collector.util import download_data
def some_function():
download_data("blah")
When I call some_function(), I get the assert. However, if I change the_caller.py to:
import collector
def some_function():
collector.util.download_data("blah")
then I get "Winning".
Why is this behaving differently, and how can I make the monkeypatch work for both scenarios?
monkeypatch can be used to patch functions dependent on the user to always return a specific value. In this example, monkeypatch. setattr is used to patch Path. home so that the known testing path Path("/abc") is always used when the test is run. This removes any dependency on the running user for testing purposes.
monkeypatch is a part of the pytest-mock library that allows you to intercept what a function would normally do, substituting its full execution with a return value of your own specification. Note that monkey patching a function call does not count as actually testing that function call!
Monkey patching is a technique used to dynamically update the behavior of a piece of code at run-time. A monkey patch (also spelled monkey-patch, MonkeyPatch) is a way to extend or modify the runtime code of dynamic languages (e.g. Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, etc.)
In Python, the term monkey patch refers to dynamic (or run-time) modifications of a class or module. In Python, we can actually change the behavior of code at run-time. We use above module (monk) in below code and change behavior of func() at run-time by assigning different value.
In general, it seems that the issue relates to how imports work in python. I'm not sure that there is a good solution.
The best work-around that I have found so far is the following:
monkeypatch.setattr('collector.util.download_data.__code__', replacement_function.__code__)
This works with both import types. One limitation is that this doesn't work with closures.
This functionality can be added to the framework via:
from _pytest.monkeypatch import monkeypatch
monkeypatch.setcode = lambda self, func_str, replacement_func: \
monkeypatch.setattr(self, func_str + ".__code__", replacement_func.__code__)
Reference: https://mail.python.org/pipermail/pytest-dev/2013-October/002386.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With