A pytest fixture wrapper for https://pypi.org/project/mock-generator
Project description
pytest-mock-generator
Installation
pip install pytest-mock-generator
or install with poetry:
poetry add pytest-mock-generator
Usage
This pytest plugin
adds the mg
fixture
which helps when writing tests that use python mocks.
Let's start with an easy example. Assume you have a module named tested_module.py
which holds a function
to process a string sent to it and then add it to a zip file:
import zipfile
def process_and_zip(zip_path, file_name, contents):
processed_contents = "processed " + contents # some complex logic
with zipfile.ZipFile(zip_path, 'w') as zip_container:
zip_container.writestr(file_name, processed_contents)
This is the unit under test, or UUT.
Although this is a very short function,
writing the test code takes a lot of time. It's the fact that the function uses
a context manager makes the testing more complex than it should be.
If you don't believe me, try to manually write mocks and asserts which verify
that zip_container.writestr
was called with the right parameters.
In any case, you start with a test skeleton:
from tests.sample.code.tested_module import process_and_zip
def test_process_and_zip(mocker, mg):
# Arrange: todo
# Act: invoking the tested code
process_and_zip('/path/to.zip', 'in_zip.txt', 'foo bar')
# Assert: todo
Now it's time to use Mock Generator instead of manually writing the 'Arrange' and 'Assert' sections.
Generating the 'Arrange' section
To generate the 'Arrange' section, simply put this code at the beginning of
your test function skeleton and run it (make sure to add the mg
fixture to
your test function):
mg.generate_uut_mocks(process_and_zip)
This will generate the 'Arrange' section for you:
# mocked dependencies
mock_ZipFile = mocker.MagicMock(name='ZipFile')
mocker.patch('tests.sample.code.tested_module.zipfile.ZipFile', new=mock_ZipFile)
The generated code is returned, printed to the console and also copied to the clipboard for your convenience. Just paste it (as simple as ctrl+V) at the start of your test function:
from tests.sample.code.tested_module import process_and_zip
def test_process_and_zip(mocker, mg):
# mocked dependencies
mock_ZipFile = mocker.MagicMock(name='ZipFile')
mocker.patch('tests.sample.code.tested_module.zipfile.ZipFile', new=mock_ZipFile)
# Act: invoking the tested code
process_and_zip('/path/to.zip', 'in_zip.txt', 'foo bar')
# Assert: todo
Excellent! Arrange section is ready.
Generating the Assert section
Now it's time to add the asserts. Add the following code at the 'Assert' step:
mg.generate_asserts(mock_ZipFile)
The mock_ZipFile
is the mock object you generated earlier.
Now execute the test function to get the assert section:
assert 1 == mock_ZipFile.call_count
mock_ZipFile.assert_called_once_with('/path/to.zip', 'w')
mock_ZipFile.return_value.__enter__.assert_called_once_with()
mock_ZipFile.return_value.__enter__.return_value.writestr.assert_called_once_with('in_zip.txt', 'processed foo bar')
mock_ZipFile.return_value.__exit__.assert_called_once_with(None, None, None)
Wow, that's a handful of asserts! Some are very useful:
- Checking that we opened the zip file with the right parameters.
- Checking that we wrote the correct data to the proper file.
- Finally, ensuring that
__enter__
and__exit__
are called, so there are no open file handles which could cause problems.
You can remove any generated line which you find unnecessary.
Paste that code right after the act phase, and you're done!
The complete test function:
from tests.sample.code.tested_module import process_and_zip
def test_process_and_zip(mocker):
# mocked dependencies
mock_ZipFile = mocker.MagicMock(name='ZipFile')
mocker.patch('tests.sample.code.tested_module.zipfile.ZipFile', new=mock_ZipFile)
# Act: invoking the tested code
process_and_zip('/path/to.zip', 'in_zip.txt', 'foo bar')
assert 1 == mock_ZipFile.call_count
mock_ZipFile.assert_called_once_with('/path/to.zip', 'w')
mock_ZipFile.return_value.__enter__.assert_called_once_with()
mock_ZipFile.return_value.__enter__.return_value.writestr.assert_called_once_with('in_zip.txt', 'processed foo bar')
mock_ZipFile.return_value.__exit__.assert_called_once_with(None, None, None)
Can you imagine the time it would have taken you to code this on your own?
What's Next
Asserting Existing Mocks
At times, you may be editing a test code already containing mocks, or you choose to write the mocks yourself, to gain some extra control.
Mock Generator can generate the assert section for standard Python mocks, even if they were not created using the Mock Generator.
Put this after the 'Act' (replace mock_obj
with your mock object name):
mg.generate_asserts(mock_obj)
Take the generated code and paste it at the 'Assert' section.
Generating the 'Arrange' and 'Assert' sections in one call
You can make the generate_uut_mocks_with_asserts
call create the
generate_asserts
code for you (instead of having to call
generate_uut_mocks
):
mg.generate_uut_mocks_with_asserts(function_under_test)
More information
Additional documentation can be found in the mock-generator pypi.
📈 Releases
You can see the list of available releases on the GitHub Releases page.
We follow Semantic Versions specification.
🛡 License
This project is licensed under the terms of the MIT
license. See LICENSE for more details.
📃 Citation
@misc{pytest-mock-generator,
author = {Peter Kogan},
title = {A pytest fixture wrapper for https://pypi.org/project/mock-generator},
year = {2021},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/pksol/pytest-mock-generator}}
}
Credits
This project was generated with python-package-template
Project details
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 pytest-mock-generator-1.0.0.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2ed4496447a2eb67f2b2804991fa642bb66d8c622e4aded5f65759ef0ebdb596 |
|
MD5 | 54d2a2312ca72d3c53e1e3493d235434 |
|
BLAKE2b-256 | 47692f5e4a5e054423a2246776a12938cef32b68515b602f83c8f5ae254721d4 |
Hashes for pytest_mock_generator-1.0.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9b780f68e62f90b2d5fb8d4a61848a72096650c6ebad7b92782e3b2acdb84e85 |
|
MD5 | 83c097c17e801c0f6566822c46d68a8b |
|
BLAKE2b-256 | 5771d8d670930020761f3aabf1955773a1f0ee1488c91809318c743d2d1e9af6 |