Python unit testing with Pytest and Mock

My favorite documentation is objective-based: I’m trying to achieve X objective, here are some examples of how library Y can help. The Pytest and Mock documentations include many examples, but the examples are not opinionated. It’s not clear which of 7 ways to achieve my objective is best.

Here are some examples I developed while contributing to the Neuroscience research platform BigNeuron. I’ve renamed the methods for clarity, but the original code can be found here: module and tests. (I’m actually using a wrapper library called Pytest-mock instead of plain Mock).

Directory structure that makes running tests easy


How do I run these tests?

python -m pytest tests/ (all tests)
python -m pytest -k filenamekeyword (tests matching keyword)
python -m pytest tests/utils/ (single test file)
python -m pytest tests/utils/ (single test method)
python -m pytest --resultlog=testlog.log tests/ (log output to file)
python -m pytest -s tests/ (print output to console)

Import statements

import mock 
import pytest
from pytest_mock import mocker
from src.jobitems import manager

Verify sub-method called with specific parameters

def test_update_jobs_fleet_capacity(mocker):
mocker.patch.object(manager, 'sub_method')
manager.sub_method.return_value = 120
manager.sub_method.assert_called_with('somestring', 1, 120)

Mock class in another module

def test_helper_class(mocker):
mocker.patch.object(manager, 'other_class')
manager.other_class.other_method.return_value = 50

Run test multiple times with array of params

@pytest.mark.parametrize('test_type, var1, var2, expect', [
('verify_max_returned', 'apple', 90, 100),
('verify_min_returned', 'orange', 2, 10)
def test_get_size(mocker, test_type, var1, var2, expect):
print("Logging test type for visibility: " + test_type)
assert fleet_manager.get_optimal_size('zone1', var1,
var2) == expect

Verify method is called with any parameter (value doesn’t matter)

manager.update_size(mock.ANY, 'var2', mock.ANY)

Override constant in config file

def test_update_config_val(monkeypatch): 
monkeypatch.setattr(config, 'WEBSITE_URL', '')
assert manager.method_that_uses_config_val() == ''

Override environment variable

def test_update_env_var(monkeypatch): 
monkeypatch.setenv('DOMAIN', 'Devo')
assert manager.method_that_uses_env_var() == 'Devo'

Verify unit test fails

def test_that_should_fail():

Verify test throws exception

def test_that_should_throw_exception():
with pytest.raises(Exception):

Skip test that fails intermittently

@pytest.mark.skipif(True, reason="Method is too slow")
def test_very_slow_method():

Create shared Mock object for all tests in module

def my_fixture():
def test_that_uses_shared_mock_obj(my_fixture):
assert manager.do_something(my_fixture, 'hello') == None

That’s it! I hope these examples help.

UPDATE June 2017: Check out Wil Cooley’s response below. He offers some helpful corrections and points out better ways to accomplish some of the tasks above. Thanks, Wil!

Exploring. Previously software @Amazon.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store