Create unittest.mock.patch target values from python omoduless instead of string wrangling
Project description
Patch Target: A tiny library for creating valid unittest.mock.patch target arguments
The ability to monkey patch modules, functions, classes, and class instances is a powerful part of testing Python code; however, the unittest.mock.patch function depends on the developer providing a precise module path AS A STRING to the object to be patched. If you refactor where your modules live or make other changes, you will find the annoying and hard-to-decipher-at-first errors pointing to an invalid module path string.
This small library, consisting of a single exported function, attempts to make using this function a more straightforward, reliably correct experience.
the patch_target
function takes 2 arguments:
- a
host_module
of typeModuleType
- and an
object_to_be_patched
, a Union ofModuleType | Callable[[Any], Any] | Type[Any]
Since you're dealing with python objects instead of strings, you get more guarantees out of the box. E.g. since you have to pass in a module instead of a string, that means you have to have successfully imported the module into your test to begin with
example:
Given a src code file like this:
# myapp.mymodule.mysubmodule
import datetime
from uuid import uuid4
def get_current_time():
return datetime.datetime.now()
def generate_new_id():
return uuid4()
You can patch the non-deterministic pieces (current time and uuid generation) like so:
from unittest.mock import patch, Mock
from myapp.my_module import my_submodule # noqa
import datetime
import uuid
from patch_target import patch_target
# using the patch decorator
@patch(patch_target(my_submodule, datetime)) # Using string paths the patch arg would be "myapp.mymodule.my_submodule.datetime"
def test_get_current_time(mock_datetime: Mock) -> None:
the_beginning_of_time = datetime.datetime(1970, 1, 1)
mock_datetime.datetime.now.return_value = the_beginning_of_time
actual = my_submodule.get_current_time()
expected = the_beginning_of_time
assert actual == expected
# using the patch context manager
def test_generate_new_id() -> None:
fake_id = "my-super-cool-id"
with patch(patch_target(my_submodule, uuid.uuid4)) as mock_uuid4: # Using string paths the patch arg would be "myapp.mymodule.my_submodule.uuid.uuid4"
mock_uuid4.return_value = fake_id
actual = my_submodule.generate_new_id()
expected = fake_id
assert actual == expected
These are obviously trivial examples, the payoff becomes even more apparent with deeply nested module structures.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for patch_target-0.1.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f69445750fa2b0cb7d7d2c65d64eb65e22cde00f3b62e6b173372444887d4fc6 |
|
MD5 | f70d09d64e44cc3cb879abd5b3a16b27 |
|
BLAKE2b-256 | c4f72e6aff3b773ec91a3c3dc84668e4d9c69d7e8572a49f40d243c0bd6e0f21 |