Mocking External Code#
To mock outside function calls with Pytest, install the pytest-mock package and use mocker as a parameter to your test function. Then you set the patch with the following syntax: mocker.patch.object(Class, "function_name", replacement_function). Note how there aren’t any parantheses for the functions - either in the string representation or the actual function. This is because if they were used, the function would be evaluated at the call, rather than passed in to the patch.object function. These are best done in setup functions rather than the test function itself.
Note: The mocker object and pytest-mock modules don’t need to be separately imported.
Example#
@pytest.fixture(params=[1, 2])
def generate_test_parameters(request, mocker):
mocker.patch.object(FeatureModel, "query", query_mock)
def query_mock(*args, **kwargs):
do_something()
Using Fixtures for Setup and Teardown#
Fixtures should be used for setup and teardown functionality, including setting up mocks. These are functions decorated with @pytest.fixture() and if you need to re-run a fixture with multiple parameters you give the decorator a params parameter. This can then be accessed via the request object passed into the fixture function, and the fixture function is itself passed into the appropriate test function(s).
Example#
@pytest.fixture(params=[1, 2])
def generate_test_parameters(request):
if request.param == 1:
do_something()
return test_params, expected_output
def test_function(generate_test_parameters):
out = function_under_test(generate_test_parameters[0])
assert out == generate_test_parameters[1]
Methods for Adding Teardowns to Fixtures#
There are two ways to add teardown functionality to Pytest fixtures:
- Change the
returnstatement to ayieldone and put all your teardown code after that. - Use the
requestobject and call.addfinalizer()with the teardown function passed in as a parameter.
Example#
# yield technique
@pytest.fixture
def receiving_user(mail_admin):
user = mail_admin.create_user()
yield user
mail_admin.delete_user(user)
# addfinalizer() technique
@pytest.fixture
def receiving_user(mail_admin, request):
user = mail_admin.create_user()
def delete_user():
mail_admin.delete_user(user)
request.addfinalizer(delete_user)
return user