Python Unit Testing Mock
Python Mock
mock
has become part of the standard library, and is imported as unittest.mock
in Python 3.6+. mock
is used to replace parts of your system under test with mock objects and make assertions about how they have been used.
Using the patch()
decorator, you are able to replace objects in your testing code with mock objects, the objects are searched in the namespace where the decorator is used. Be cautious about the Order of the decorators, the patching is done from the bottom upwards.
In the below example, while executing the test_function()
, the read_csv
, write_csv
and os.path.exists
are replaced with mock objects, and returns the values we specify. The actual functions are not executed.
from unittest.mock import patch
import os
import pandas as pd
def target_func(filepath):
if os.path.exists(filepath):
df = pd.read_csv("fake.csv")
df.to_csv("foo.csv")
return "File path is found and CSVs are read and wrote."
else:
return "Not Found"
@patch('pandas.read_csv')
@patch('pandas.DataFrame.to_csv')
@patch('os.path.exists')
def test_func(mock_path_exists, mock_df_to_csv, mock_read_csv):
mock_read_csv.return_value = pd.DataFrame()
mock_path_exists.return_value = True
res = target_func('sth')
print(res)
test_func()
File path is found and CSVs are read and wrote.
Another cleaner way to use mock
is to replace the objects in the decorator itself. By defining a gerneral object, no matter how the actual functions are called, we ignore the inputs and return the values we specify. In this case, to_csv
does not even have a RANDOM_PARAM
argument, but the code doesn’t fail.
from unittest.mock import patch
import os
import pandas as pd
def Mock_None(*args, **kwargs):
return None
def target_func():
return pd.read_csv(), pd.DataFrame.to_csv(RANDOM_PARAM=False), os.path.exists()
# Mock_None is a function (object), which is used as the mock object here
@patch('pandas.read_csv', Mock_None)
@patch('pandas.DataFrame.to_csv', Mock_None)
@patch('os.path.exists', Mock_None)
def test_func():
res = target_func()
print(res)
test_func()
(None, None, None)