Pytest — How to test that a function is called with specific parameters?
Unit tests are written to test single possible units of your system. When you interact with an external system, such as reading a file from AWS S3, your tests must run without any dependency on this external system. The standard testing practice for this use case is to mock the function interacting with this external system and ensure everything else works as expected.
To illustrate this example, Let’s start with a simple Python function that reads data from a CSV and writes it to another CSV.
def read_data(input_path=None, output_path=None):
input_path = input_path or "input_data/data.csv"
output_path = output_path or "output_data/output.csv"
with open(input_path, "r") as fin:
with open(output_path, "w") as fout:
fout.write(fin.read())
The test case we are interested in is to ensure that the open
function is called with the passed param and not the default. Since open
is a Python built-in, we don't have to test its logic explicitly.
Let’s start by mocking the builtins.open
built-in mock_open
function using the patch
decorator.
import pytest
import scriptfrom unittest.mock import patch, mock_open, call@patch("builtins.open", new_callable=mock_open, read_data="data")
def test_file_logic(mock_open_obj):
read_data(input_path, output_path)
Next, we have to ensure the read_data
function calls the open method with the expected input and output path. assert_has_calls
is a function of the mock object, which will check the trace of calls and ensure that the call with specific params is present.
import pytest
import script
from unittest.mock import patch, mock_open, call @patch("builtins.open", new_callable=mock_open, read_data="data") def test_file_logic(mock_open_obj):
read_data(input_path, output_path)
mock_open_obj.assert_has_calls([call(expected_output_path, "w"),
call(expected_input_path, "r")],
any_order=True)
The any_order
is important because open go through various stack trace like __enter__
and doesn't appear in the order.
Originally published at https://thelearning.dev.