What is Python mocking?

svg viewer

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.mock is the mock library. For older versions, you’ll need to install the mock library using pip.

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_count is used to see how many times the method is called.
  • .call_args tells the arguments used when the method is called.
  • .call_args gives a list of arguments given to the call method call.
  • .method_calls lists the methods called to the real_obj library.

Implementation

Below is a simplified example to demonstrate how a mock object works.

from unittest.mock import Mock
import pandas as pd
my_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 data frameA two-dimensional tabular data structure. is mocked using a 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.

Copyright ©2024 Educative, Inc. All rights reserved