You can use patch
from the mock
module. Here is an example:
with patch('yourpackage.b.Real') as fake_real:
fake_real.return_value = Fake()
foo = b.someClass()
foo.somemethod()
The issue is that when you do -
from a
import Real, Fake
If initialize
script is another .py
module/script at runs at the start of your original program , then you can use the below -
if env == 'dev':
import a
a.Real = a.Fake
Though I would suggest that a better way would be to do this in your a
module itself, by making it possible to check the env
in that module, as -
if <someothermodule>.env == 'dev':
Real = Fake
Monkey Patching in Python (Dynamic Behavior),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.,Writing code in comment? Please use ide.geeksforgeeks.org, generate link and share the link here.,Memoization using decorators in Python
Examples:
Output: monkey_f() is being called
Monkey Patching is an exciting topic of Python. Monkey-patching is a term that refers to modifying a class or module at a run time. In simple words, a class or module's work can be changed at the runtime. Let's understand this concept by real-life example.,To add the divide() method to MonkeyPatch class, simply assign the divide function to MonkeyPatch.,We have discussed how we can achieve the monkey-patching in Python. But it consists of few disadvantages and should be used carefully. It is not good to use in application design because it distinguishes the source code on disk and the observed behavior. Developer can be confused while debugging.,The newly created function would be available in the MonkeyPatch class. Let's see the following example.
30
[('__init__', > ), ('add', > )]
[('__init__', > ), ('subtraction', > )]
monkey_f() is being called
1. Modifying the behavior of a function or the property of a class for a test e.g. there is an API call or database connection you will not make for a test but you know what the expected output should be. Use monkeypatch.setattr to patch the function or property with your desired testing behavior. This can include your own functions. Use monkeypatch.delattr to remove the function or property for the test.,2. Modifying the values of dictionaries e.g. you have a global configuration that you want to modify for certain test cases. Use monkeypatch.setitem to patch the dictionary for the test. monkeypatch.delitem can be used to remove items.,All modifications will be undone after the requesting test function or fixture has finished. The raising parameter determines if a KeyError or AttributeError will be raised if the target of the set/deletion operation does not exist.,3. Modifying environment variables for a test e.g. to test program behavior if an environment variable is missing, or to set multiple values to a known variable. monkeypatch.setenv and monkeypatch.delenv can be used for these patches.
monkeypatch.setattr(obj, name, value, raising = True)
monkeypatch.setattr("somemodule.obj.name", value, raising = True)
monkeypatch.delattr(obj, name, raising = True)
monkeypatch.setitem(mapping, name, value)
monkeypatch.delitem(obj, name, raising = True)
monkeypatch.setenv(name, value, prepend = None)
monkeypatch.delenv(name, raising = True)
monkeypatch.syspath_prepend(path)
monkeypatch.chdir(path)
monkeypatch.context()
# contents of test_module.py with source code and the test
from pathlib
import Path
def getssh():
""
"Simple function to return expanded homedir ssh path."
""
return Path.home() / ".ssh"
def test_getssh(monkeypatch):
# mocked
return function to replace Path.home
# always
return '/abc'
def mockreturn():
return Path("/abc")
# Application of the monkeypatch to replace Path.home
# with the behavior of mockreturn defined above.
monkeypatch.setattr(Path, "home", mockreturn)
# Calling getssh() will use mockreturn in place of Path.home
#
for this test with the monkeypatch.
x = getssh()
assert x == Path("/abc/.ssh")
# contents of app.py, a simple API retrieval example
import requests
def get_json(url):
""
"Takes a URL, and returns the JSON."
""
r = requests.get(url)
return r.json()
# contents of test_app.py, a simple test
for our API retrieval
#
import requests
for the purposes of monkeypatching
import requests
# our app.py that includes the get_json()
function
# this is the previous code block example
import app
# custom class to be the mock
return value
# will override the requests.Response returned from requests.get
class MockResponse:
# mock json() method always returns a specific testing dictionary
@staticmethod
def json():
return {
"mock_key": "mock_response"
}
def test_get_json(monkeypatch):
# Any arguments may be passed and mock_get() will always
return our
# mocked object, which only has the.json() method.
def mock_get( * args, ** kwargs):
return MockResponse()
# apply the monkeypatch
for requests.get to mock_get
monkeypatch.setattr(requests, "get", mock_get)
# app.get_json, which contains requests.get, uses the monkeypatch
result = app.get_json("https://fakeurl")
assert result["mock_key"] == "mock_response"
# contents of test_app.py, a simple test
for our API retrieval
import pytest
import requests
# app.py that includes the get_json()
function
import app
# custom class to be the mock
return value of requests.get()
class MockResponse:
@staticmethod
def json():
return {
"mock_key": "mock_response"
}
# monkeypatched requests.get moved to a fixture
@pytest.fixture
def mock_response(monkeypatch):
""
"Requests.get() mocked to return {'mock_key':'mock_response'}."
""
def mock_get( * args, ** kwargs):
return MockResponse()
monkeypatch.setattr(requests, "get", mock_get)
# notice our test uses the custom fixture instead of monkeypatch directly
def test_get_json(mock_response):
result = app.get_json("https://fakeurl")
assert result["mock_key"] == "mock_response"
# contents of conftest.py
import pytest
@pytest.fixture(autouse = True)
def no_requests(monkeypatch):
""
"Remove requests.sessions.Session.request for all tests."
""
monkeypatch.delattr("requests.sessions.Session.request")
In this case, "monkey patching" means adding a new variable or method to a class after it's been defined. For instance, say we defined class A as,These additions are available on all instances of that class (or its subclasses) automatically. For example:,But how do we add this as a method in A? That's simple we just essentially place that function into A with an assignment statement.,The function get_num shall be available to all existing (already created) as well to the new instances of A
In this case, "monkey patching" means adding a new variable or method to a class after it's been defined. For instance, say we defined class A
as
class A(object):
def __init__(self, num):
self.num = num
def __add__(self, other):
return A(self.num + other.num)
But now we want to add another function later in the code. Suppose this function is as follows.
def get_num(self):
return self.num
But how do we add this as a method in A
? That's simple we just essentially place that function into A
with an assignment statement.
A.get_num = get_num