What is Python mocking?
Testing is one of the most crucial phases before the deployment of an application. A developer usually has to test all the attributes and methods of an application before deeming it fit for use. Sometimes, the complex structure of the program or unpredictable dependencies can make it hard to make tests for the intended program.
Mock
To solve this issue, Python has introduced mocking. A mock object is used to control the behavior of the real objects, which are difficult to include in the test. The mock object imitates these real objects to make the testing easier, more efficient, and faster. There are multiple scenarios where it might be useful to use a mock object:
- The object returns a variable/non-deterministic result at every run.
- The object possesses a state that is difficult to recreate.
- The object is sluggish.
- The object does not exist yet.
- The object would have to include extra attributes and methods for testing purposes, which are useless for the actual program
For Python versions Python3.3 and up,
unittest.mockis the mock library. For older versions, you’ll need to install the mock library usingpip.
pip install mock
Using unittest.mock
You can import the library in the following manner:
from unittest.mock import Mock
Moving forward, you can make a mock object to imitate any other object in your program. To do this, initialize a variable with Mock():
my_mock = Mock()
You can use the my_mock object as an argument to a function or to redefine an object:
fun(my_mock)
real_obj = my_mock
When you do this, your mock object behaves precisely like the real_object. You can call all the functions and attributes of your real object(real_obj) using your mock object(my_mock):
my_mock.doThis()
my_mock.doThat(arg1, arg2, arg3)
There are two caveats to keep in mind when using mock methods:
- The mock methods can take any arguments given to it, unlike the real methods.
- The return value from a mock method is a mock object.
To inspect if the methods are working correctly, the mock library allows us the assert the functions called using mock objects. There are four types of assertions:
.assert_called()
.assert_called_once()
.assert_called_with()
.assert_called_once_with()
.assert_called()is used to check if the method is executed; whereas,.assert_called_once()is used if the method is only executed one time..assert_called_with()is used to check if the method is called with a particular set of arguments..assert_called_once_with()is used to check if the method is called with a particular set of arguments.
The mock library also lets you analyze how the object method is performed by using some particular methods:
.call_count
.call_args
.call_args_list
.method_calls
.call_countis used to see how many times the method is called..call_argstells the arguments used when the method is called..call_argsgives a list of arguments given to the call method call..method_callslists the methods called to thereal_objlibrary.
Implementation
Below is a simplified example to demonstrate how a mock object works.
from unittest.mock import Mockimport pandas as pdmy_mock = Mock()my_df = my_mock.DataFrame([["carnivore", "shark"],["carnivore", "lion"],["herbivore", "goat"],["herbivore", "sheep"]],columns = ["type", "name"])print(my_df)my_df.set_index("type", inplace=True)print(my_df.set_index.assert_called_with("type", inplace=True))print(my_df.set_index.call_count)print(my_df.set_index.call_args)
In this example, a Pandas my_mock object. The mocked data frame is then assigned to the my_df variable. my_df now mimics the real object and can use all the functions of the real object.
.set_index() method is called with argument "type, inplace=True".
To check if the method was executed correctly, the .assert_called_with() method is used. Since the object is called with the same arguments as mentioned in the .asser_called_with() statement, the output is None. In the case that the arguments did not match, an AssertionError would be raised.
To analyze the execution of .set_index() method, .call_count is used to display the number of times .set_index() is called. Moreover, .call_args() is used to display the arguments given to the .set_index() method.
Free Resources