Mocking and Fixtures in Python (87/100 Days of Python)

Martin Mirakyan
3 min readMar 29, 2023

--

Day 87 of the “100 Days of Python” blog post series covering mocking and fixtures with Pytest

Mocking and fixtures are two important concepts in Python testing that can help simplify and streamline the testing process. In this tutorial, we’ll cover the basics of mocking and fixtures and show you how to use them in your own tests.

What is Mocking?

Mocking is the process of creating simulated objects, or “mocks”, that mimic the behavior of real objects in your program. Mocks are often used in testing to simulate the behavior of external dependencies, such as a database or a web service, so that your tests can run independently of these dependencies.

In Python, you can use the unittest.mock module to create mock objects. Mock objects can be configured to return specific values, raise specific exceptions, or have specific attributes, which makes them highly customizable and adaptable to your testing needs.

What are Fixtures?

Fixtures are objects that are created before tests are run and can be reused across multiple tests. Fixtures can be used to set up the environment for testing, such as creating a database connection or setting up a test server.

In Python, you can use the pytest testing framework to define fixtures. Fixtures are defined using the @pytest.fixture decorator and can be parameterized to accept arguments that are passed in from tests.

How to Use Mocking and Fixtures in Python Tests

To use mocking and fixtures in your tests, you’ll first need to install the necessary packages. You can install the pytest testing framework and the unittest.mock module using pip:

pip install pytest
pip install pytest-mock

Once you’ve installed the necessary packages, you can define fixtures in your tests using the @pytest.fixture decorator. For example, here's a fixture that creates a temporary file for testing:

import pytest
import tempfile

@pytest.fixture
def temp_file():
""" Create a temporary file for testing """
with tempfile.NamedTemporaryFile() as file:
yield file.name

In this example, the temp_file fixture creates a temporary file using the tempfile.NamedTemporaryFile function and returns the file's name. The yield keyword is used to indicate that the fixture is a generator function that will be run before and after each test that uses it. You can then use the temp_file fixture in your tests like this:

def test_write_to_file(temp_file):
""" Test writing to a temporary file """
with open(temp_file, 'w') as file:
file.write('Hello, world!')
with open(temp_file) as file:
assert file.read() == 'Hello, world!'

In this example, the test_write_to_file function uses the temp_file fixture as an argument. The fixture creates a temporary file, which is then used to test writing and reading data to and from the file.

You can also use the pytest-mock package to create mock objects in your tests. For example, here's a test that uses a mock to simulate the behavior of an external dependency:

from unittest.mock import MagicMock

import requests


def download_data():
""" Download data from an external service """
response = requests.get('https://google.com')
return response.json()['data']


def test_download_data(mocker):
""" Test downloading data from an external service """
# Create a mock object for the requests library
mock_requests = MagicMock()
mocker.patch('requests.get', mock_requests)

# Set the mock object to return a specific response
response = {'data': 'Hello, world!'}
mock_requests.return_value.json.return_value = response

# Call the function that downloads data from the external service
data = download_data()

# Verify that the function returns the expected data
print('data:', data)
print(response)
assert data == response['data']

In this example, the test_download_data function uses the mocker fixture provided by the pytest-mock package to create a mock object for the requests library. The mocker.patch method is used to patch the requests.get method with the mock object. This ensures that when the download_data function calls requests.get, it will use the mock object instead of the real requests library.

The mock object is then configured to return a specific response when the json method is called. This allows the test to simulate the behavior of the external service without actually making a network request.

Finally, the download_data function is called and the result is compared to the expected response.

What’s next?

--

--

Martin Mirakyan
Martin Mirakyan

Written by Martin Mirakyan

Software Engineer | Machine Learning | Founder of Profound Academy (https://profound.academy)

No responses yet