26 min read

In this article by Daniel Arbuckle, author of the book Learning Python Testing, you’ll learn how by using the unittest.mock package, you can easily perform the following:

  • Replace functions and objects in your own code or in external packages.
  • Control how replacement objects behave. You can control what return values they provide, whether they raise an exception, even whether they make any calls to other functions, or create instances of other objects.
  • Check whether the replacement objects were used as you expected: whether functions or methods were called the correct number of times, whether the calls occurred in the correct order, and whether the passed parameters were correct.

(For more resources related to this topic, see here.)

Mock objects in general

All right, before we get down to the nuts and bolts of unittest.mock, let’s spend a few moments talking about mock objects overall.

Broadly speaking, mock objects are any objects that you can use as substitutes in your test code, to keep your tests from overlapping and your tested code from infiltrating the wrong tests. However, like most things in programming, the idea works better when it has been formalized into a well-designed library that you can call on when you need it. There are many such libraries available for most programming languages.

Over time, the authors of mock object libraries have developed two major design patterns for mock objects: in one pattern, you can create a mock object and perform all of the expected operations on it. The object records these operations, and then you put the object into playback mode and pass it to your code. If your code fails to duplicate the expected operations, the mock object reports a failure.

In the second pattern, you can create a mock object, do the minimal necessary configuration to allow it to mimic the real object it replaces, and pass it to your code. It records how the code uses it, and then you can perform assertions after the fact to check whether your code used the object as expected.

The second pattern is slightly more capable in terms of the tests that you can write using it but, overall, either pattern works well.

Mock objects according to unittest.mock

Python has several mock object libraries; as of Python 3.3, however, one of them has been crowned as a member of the standard library. Naturally that’s the one we’re going to focus on. That library is, of course, unittest.mock.

The unittest.mock library is of the second sort, a record-actual-use-and-then-assert library. The library contains several different kinds of mock objects that, between them, let you mock almost anything that exists in Python. Additionally, the library contains several useful helpers that simplify assorted tasks related to mock objects, such as temporarily replacing real objects with mocks.

Standard mock objects

The basic element of unittest.mock is the unittest.mock.Mock class. Even without being configured at all, Mock instances can do a pretty good job of pretending to be some other object, method, or function.

There are many mock object libraries for Python; so, strictly speaking, the phrase “mock object” could mean any object that was created by any of these libraries.

Mock objects can pull off this impersonation because of a clever, somewhat recursive trick. When you access an unknown attribute of a mock object, instead of raising an AttributeError exception, the mock object creates a child mock object and returns that. Since mock objects are pretty good at impersonating other objects, returning a mock object instead of the real value works at least in the common case.

Similarly, mock objects are callable; when you call a mock object as a function or method, it records the parameters of the call and then, by default, returns a child mock object.

A child mock object is a mock object in its own right, but it knows that it’s connected to the mock object it came from—its parent. Anything you do to the child is also recorded in the parent’s memory. When the time comes to check whether the mock objects were used correctly, you can use the parent object to check on all of its descendants.

Example: Playing with mock objects in the interactive shell (try it for yourself!):

$ python3.4
Python 3.4.0 (default, Apr 2 2014, 08:10:08)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from unittest.mock import Mock, call
>>> mock = Mock()
>>> mock.x
<Mock name='mock.x' id='140145643647832'>
>>> mock.x
<Mock name='mock.x' id='140145643647832'>
>>> mock.x('Foo', 3, 14)
<Mock name='mock.x()' id='140145643690640'>
>>> mock.x('Foo', 3, 14)
<Mock name='mock.x()' id='140145643690640'>
>>> mock.x('Foo', 99, 12)
<Mock name='mock.x()' id='140145643690640'>
>>> mock.y(mock.x('Foo', 1, 1))
<Mock name='mock.y()' id='140145643534320'>
>>> mock.method_calls
[call.x('Foo', 3, 14),
call.x('Foo', 3, 14),
call.x('Foo', 99, 12),
call.x('Foo', 1, 1),
call.y(<Mock name='mock.x()' id='140145643690640'>)]
>>> mock.assert_has_calls([call.x('Foo', 1, 1)])
>>> mock.assert_has_calls([call.x('Foo', 1, 1), call.x('Foo', 99, 12)])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.4/unittest/mock.py", line 792, in assert_has_
calls
) from cause
AssertionError: Calls not found.
Expected: [call.x('Foo', 1, 1), call.x('Foo', 99, 12)]
Actual: [call.x('Foo', 3, 14),
call.x('Foo', 3, 14),
call.x('Foo', 99, 12),
call.x('Foo', 1, 1),
call.y(<Mock name='mock.x()' id='140145643690640'>)]
>>> mock.assert_has_calls([call.x('Foo', 1, 1),
... call.x('Foo', 99, 12)], any_order = True)
>>> mock.assert_has_calls([call.y(mock.x.return_value)])

There are several important things demonstrated in this interactive session.

First, notice that the same mock object was returned each time that we accessed mock.x. This always holds true: if you access the same attribute of a mock object, you’ll get the same mock object back as the result.

The next thing to notice might seem more surprising. Whenever you call a mock object, you get the same mock object back as the return value. The returned mock isn’t made new for every call, nor is it unique for each combination of parameters. We’ll see how to override the return value shortly but, by default, you get the same mock object back every time you call a mock object. This mock object can be accessed using the return_value attribute name, as you might have noticed from the last statement of the example.

The unittest.mock package contains a call object that helps to make it easier to check whether the correct calls have been made. The call object is callable, and takes note of its parameters in a way similar to mock objects, making it easy to compare it to a mock object’s call history. However, the call object really shines when you have to check for calls to descendant mock objects. As you can see in the previous example, while call(‘Foo’, 1, 1) will match a call to the parent mock object, if the call used these parameters, call.x(‘Foo’, 1, 1), it matches a call to the child mock object named x. You can build up a long chain of lookups and invocations. For example:

>>> mock.z.hello(23).stuff.howdy('a', 'b', 'c')
<Mock name='mock.z.hello().stuff.howdy()' id='140145643535328'>
>>> mock.assert_has_calls([
... call.z.hello().stuff.howdy('a', 'b', 'c')
... ])
>>>

Notice that the original invocation included hello(23), but the call specification wrote it simply as hello(). Each call specification is only concerned with the parameters of the object that was finally called after all of the lookups. The parameters of intermediate calls are not considered. That’s okay because they always produce the same return value anyway unless you’ve overridden that behavior, in which case they probably don’t produce a mock object at all.

You might not have encountered an assertion before. Assertions have one job, and one job only: they raise an exception if something is not as expected. The assert_has_calls method, in particular, raises an exception if the mock object’s history does not include the specified calls. In our example, the call history matches, so the assertion method doesn’t do anything visible.

You can check whether the intermediate calls were made with the correct parameters, though, because the mock object recorded a call immediately to mock.z.hello(23) before it recorded a call to mock.z.hello().stuff.howdy(‘a’, ‘b’, ‘c’):

>>> mock.mock_calls.index(call.z.hello(23))
6
>>> mock.mock_calls.index(call.z.hello().stuff.howdy('a', 'b', 'c'))
7

This also points out the mock_calls attribute that all mock objects carry. If the various assertion functions don’t quite do the trick for you, you can always write your own functions that inspect the mock_calls list and check whether things are or are not as they should be. We’ll discuss the mock object assertion methods shortly.

Non-mock attributes

What if you want a mock object to give back something other than a child mock object when you look up an attribute? It’s easy; just assign a value to that attribute:

>>> mock.q = 5
>>> mock.q
5

There’s one other common case where mock objects’ default behavior is wrong: what if accessing a particular attribute is supposed to raise an AttributeError? Fortunately, that’s easy too:

>>> del mock.w
>>> mock.w
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.4/unittest/mock.py", line 563, in __getattr__
raise AttributeError(name)
AttributeError: w

Non-mock return values and raising exceptions

Sometimes, actually fairly often, you’ll want mock objects posing as functions or methods to return a specific value, or a series of specific values, rather than returning another mock object.

To make a mock object always return the same value, just change the return_value attribute:

>>> mock.o.return_value = 'Hi'
>>> mock.o()
'Hi'
>>> mock.o('Howdy')
'Hi'

If you want the mock object to return different value each time it’s called, you need to assign an iterable of return values to the side_effect attribute instead, as follows:

>>> mock.p.side_effect = [1, 2, 3]
>>> mock.p()
1
>>> mock.p()
2
>>> mock.p()
3
>>> mock.p()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.4/unittest/mock.py", line 885, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "/usr/lib64/python3.4/unittest/mock.py", line 944, in _mock_call
result = next(effect)
StopIteration

If you don’t want your mock object to raise a StopIteration exception, you need to make sure to give it enough return values for all of the invocations in your test. If you don’t know how many times it will be invoked, an infinite iterator such as itertools.count might be what you need. This is easily done:

>>> mock.p.side_effect = itertools.count()

If you want your mock to raise an exception instead of returning a value, just assign the exception object to side_effect, or put it into the iterable that you assign to side_effect:

>>> mock.e.side_effect = [1, ValueError('x')]
>>> mock.e()
1
>>> mock.e()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python3.4/unittest/mock.py", line 885, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "/usr/lib64/python3.4/unittest/mock.py", line 946, in _mock_call
raise result
ValueError: x

The side_effect attribute has another use, as well that we’ll talk about.

Mocking class or function details

Sometimes, the generic behavior of mock objects isn’t a close enough emulation of the object being replaced. This is particularly the case when it’s important that they raise exceptions when used improperly, since mock objects are usually happy to accept any usage.

The unittest.mock package addresses this problem using a technique called speccing. If you pass an object into unittest.mock.create_autospec, the returned value will be a mock object, but it will do its best to pretend that it’s the same object you passed into create_autospec. This means that it will:

  • Raise an AttributeError if you attempt to access an attribute that the original object doesn’t have, unless you first explicitly assign a value to that attribute
  • Raise a TypeError if you attempt to call the mock object when the original object wasn’t callable
  • Raise a TypeError if you pass the wrong number of parameters or pass a keyword parameter that isn’t viable if the original object was callable
  • Trick isinstance into thinking that the mock object is of the original object’s type

Mock objects made by create_autospec share this trait with all of their children as well, which is usually what you want. If you really just want a specific mock to be specced, while its children are not, you can pass the template object into the Mock constructor using the spec keyword.

Here’s a short demonstration of using create_autospec:

>>> from unittest.mock import create_autospec
>>> x = Exception('Bad', 'Wolf')
>>> y = create_autospec(x)
>>> isinstance(y, Exception)
True
>>> y
<NonCallableMagicMock spec='Exception' id='140440961099088'>

Mocking function or method side effects

Sometimes, for a mock object to successfully take the place of a function or method means that the mock object has to actually perform calls to other functions, or set variable values, or generally do whatever a function can do.

This need is less common than you might think, and it’s also somewhat dangerous for testing purposes because, when your mock objects can execute arbitrary code, there’s a possibility that they stop being a simplifying tool for enforcing test isolation, and become a complex part of the problem instead.

Having said that, there are still times when you need a mocked function to do something more complex than simply returning a value, and we can use the side_effect attribute of mock objects to achieve this. We’ve seen side_effect before, when we assigned an iterable of return values to it.

If you assign a callable to side_effect, this callable will be called when the mock object is called and passed the same parameters. If the side_effect function raises an exception, this is what the mock object does as well; otherwise, the side_effect return value is returned by the mock object.

In other words, if you assign a function to a mock object’s side_effect attribute, this mock object in effect becomes that function with the only important difference being that the mock object still records the details of how it’s used.

The code in a side_effect function should be minimal, and should not try to actually do the job of the code the mock object is replacing. All it should do is perform any expected externally visible operations and then return the expected result.Mock object assertion methods

As we saw in the Standard mock objects section, you can always write code that checks the mock_calls attribute of mock objects to see whether or not things are behaving as they should. However, there are some particularly common checks that have already been written for you, and are available as assertion methods of the mock objects themselves. As is normal for assertions, these assertion methods return None if they pass, and raise an AssertionError if they fail.

The assert_called_with method accepts an arbitrary collection of arguments and keyword arguments, and raises an AssertionError unless these parameters were passed to the mock the last time it was called.

The assert_called_once_with method behaves like assert_called_with, except that it also checks whether the mock was only called once and raises AssertionError if that is not true.

The assert_any_call method accepts arbitrary arguments and keyword arguments, and raises an AssertionError if the mock object has never been called with these parameters.

We’ve already seen the assert_has_calls method. This method accepts a list of call objects, checks whether they appear in the history in the same order, and raises an exception if they do not. Note that “in the same order” does not necessarily mean “next to each other.” There can be other calls in between the listed calls as long as all of the listed calls appear in the proper sequence. This behavior changes if you assign a true value to the any_order argument. In that case, assert_has_calls doesn’t care about the order of the calls, and only checks whether they all appear in the history.

The assert_not_called method raises an exception if the mock has ever been called.

Mocking containers and objects with a special behavior

One thing the Mock class does not handle is the so-called magic methods that underlie Python’s special syntactic constructions: __getitem__, __add__, and so on. If you need your mock objects to record and respond to magic methods—in other words, if you want them to pretend to be container objects such as dictionaries or lists, or respond to mathematical operators, or act as context managers or any of the other things where syntactic sugar translates it into a method call underneath—you’re going to use unittest.mock.MagicMock to create your mock objects.

There are a few magic methods that are not supported even by MagicMock, due to details of how they (and mock objects) work: __getattr__, __setattr__, __init__ , __new__, __prepare__, __instancecheck__, __subclasscheck__, and __del__.

Here’s a simple example in which we use MagicMock to create a mock object supporting the in operator:

>>> from unittest.mock import MagicMock
>>> mock = MagicMock()
>>> 7 in mock
False
>>> mock.mock_calls
[call.__contains__(7)]
>>> mock.__contains__.return_value = True
>>> 8 in mock
True
>>> mock.mock_calls
[call.__contains__(7), call.__contains__(8)]

Things work similarly with the other magic methods. For example, addition:

>>> mock + 5
<MagicMock name='mock.__add__()' id='140017311217816'>
>>> mock.mock_calls
[call.__contains__(7), call.__contains__(8), call.__add__(5)]

Notice that the return value of the addition is a mock object, a child of the original mock object, but the in operator returned a Boolean value. Python ensures that some magic methods return a value of a particular type, and will raise an exception if that requirement is not fulfilled. In these cases, MagicMock’s implementations of the methods return a best-guess value of the proper type, instead of a child mock object.

There’s something you need to be careful of when it comes to the in-place mathematical operators, such as += (__iadd__) and |= (__ior__), and that is the fact that MagicMock handles them somewhat strangely. What it does is still useful, but it might well catch you by surprise:

>>> mock += 10
>>> mock.mock_calls
[]

What was that? Did it erase our call history? Fortunately, no, it didn’t. What it did was assign the child mock created by the addition operation to the variable called mock. That is entirely in accordance with how the in-place math operators are supposed to work. Unfortunately, it has still cost us our ability to access the call history, since we no longer have a variable pointing at the parent mock object.

Make sure that you have the parent mock object set aside in a variable that won’t be reassigned, if you’re going to be checking in-place math operators. Also, you should make sure that your mocked in-place operators return the result of the operation, even if that just means return self.return_value, because otherwise Python will assign None to the left-hand variable.

There’s another detailed way in which in-place operators work that you should keep in mind:

>>> mock = MagicMock()
>>> x = mock
>>> x += 5
>>> x
<MagicMock name='mock.__iadd__()' id='139845830142216'>
>>> x += 10
>>> x
<MagicMock name='mock.__iadd__().__iadd__()' id='139845830154168'>
>>> mock.mock_calls
[call.__iadd__(5), call.__iadd__().__iadd__(10)]

Because the result of the operation is assigned to the original variable, a series of in-place math operations builds up a chain of child mock objects. If you think about it, that’s the right thing to do, but it is rarely what people expect at first.

Mock objects for properties and descriptors

There’s another category of things that basic Mock objects don’t do a good job of emulating: descriptors.

Descriptors are objects that allow you to interfere with the normal variable access mechanism. The most commonly used descriptors are created by Python’s property built-in function, which simply allows you to write functions to control getting, setting, and deleting a variable.

To mock a property (or other descriptor), create a unittest.mock.PropertyMock instance and assign it to the property name. The only complication is that you can’t assign a descriptor to an object instance; you have to assign it to the object’s type because descriptors are looked up in the type without first checking the instance.

That’s not hard to do with mock objects, fortunately:

>>> from unittest.mock import PropertyMock
>>> mock = Mock()
>>> prop = PropertyMock()
>>> type(mock).p = prop
>>> mock.p
<MagicMock name='mock()' id='139845830215328'>
>>> mock.mock_calls
[]
>>> prop.mock_calls
[call()]
>>> mock.p = 6
>>> prop.mock_calls
[call(), call(6)]

The thing to be mindful of here is that the property is not a child of the object named mock. Because of this, we have to keep it around in its own variable because otherwise we’d have no way of accessing its history.

The PropertyMock objects record variable lookup as a call with no parameters, and variable assignment as a call with the new value as a parameter.

You can use a PropertyMock object if you actually need to record variable accesses in your mock object history. Usually you don’t need to do that, but the option exists.

Even though you set a property by assigning it to an attribute of a type, you don’t have to worry about having your PropertyMock objects bleed over into other tests. Each Mock you create has its own type object, even though they all claim to be of the same class:

>>> type(Mock()) is type(Mock())
False

Thanks to this feature, any changes that you make to a mock object’s type object are unique to that specific mock object.

Mocking file objects

It’s likely that you’ll occasionally need to replace a file object with a mock object. The unittest.mock library helps you with this by providing mock_open, which is a factory for fake open functions. These functions have the same interface as the real open function, but they return a mock object that’s been configured to pretend that it’s an open file object.

This sounds more complicated than it is. See for yourself:

>>> from unittest.mock import mock_open
>>> open = mock_open(read_data = 'moose')
>>> with open('/fake/file/path.txt', 'r') as f:
... print(f.read())
...
moose

If you pass a string value to the read_data parameter, the mock file object that eventually gets created will use that value as the data source when its read methods get called. As of Python 3.4.0, read_data only supports string objects, not bytes.

If you don’t pass read_data, read method calls will return an empty string.

The problem with the previous code is that it makes the real open function inaccessible, and leaves a mock object lying around where other tests might stumble over it. Read on to see how to fix these problems.

Replacing real code with mock objects

The unittest.mock library gives a very nice tool for temporarily replacing objects with mock objects, and then undoing the change when our test is done. This tool is unittest.mock.patch.

There are a lot of different ways in which that patch can be used: it works as a context manager, a function decorator, and a class decorator; additionally, it can create a mock object to use for the replacement or it can use the replacement object that you specify. There are a number of other optional parameters that can further adjust the behavior of the patch.

Basic usage is easy:

>>> from unittest.mock import patch, mock_open
>>> with patch('builtins.open', mock_open(read_data = 'moose')) as mock:
... with open('/fake/file.txt', 'r') as f:
... print(f.read())
...
moose
>>> open
<built-in function open>

As you can see, patch dropped the mock open function created by mock_open over the top of the real open function; then, when we left the context, it replaced the original for us automatically.

The first parameter of patch is the only one that is required. It is a string describing the absolute path to the object to be replaced. The path can have any number of package and subpackage names, but it must include the module name and the name of the object inside the module that is being replaced. If the path is incorrect, patch will raise an ImportError, TypeError, or AttributeError, depending on what exactly is wrong with the path.

If you don’t want to worry about making a mock object to be the replacement, you can just leave that parameter off:

>>> import io
>>> with patch('io.BytesIO'):
... x = io.BytesIO(b'ascii data')
... io.BytesIO.mock_calls
[call(b'ascii data')]

The patch function creates a new MagicMock for you if you don’t tell it what to use for the replacement object. This usually works pretty well, but you can pass the new parameter (also the second parameter, as we used it in the first example of this section) to specify that the replacement should be a particular object; or you can pass the new_callable parameter to make patch use the value of that parameter to create the replacement object.

We can also force the patch to use create_autospec to make the replacement object, by passing autospec=True:

>>> with patch('io.BytesIO', autospec = True):
... io.BytesIO.melvin
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/usr/lib64/python3.4/unittest/mock.py", line 557, in __getattr__
raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'melvin'

The patch function will normally refuse to replace an object that does not exist; however, if you pass it create=True, it will happily drop a mock object wherever you like. Naturally, this is not compatible with autospec=True.

The patch function covers the most common cases. There are a few related functions that handle less common but still useful cases.

The patch.object function does the same thing as patch, except that, instead of taking the path string, it accepts an object and an attribute name as its first two parameters. Sometimes this is more convenient than figuring out the path to an object. Many objects don’t even have valid paths (for example, objects that exist only in a function local scope), although the need to patch them is rarer than you might think.

The patch.dict function temporarily drops one or more objects into a dictionary under specific keys. The first parameter is the target dictionary; the second is a dictionary from which to get the key and value pairs to put into the target. If you pass clear=True, the target will be emptied before the new values are inserted. Notice that patch.dict doesn’t create the replacement values for you. You’ll need to make your own mock objects, if you want them.

Mock objects in action

That was a lot of theory interspersed with unrealistic examples. Let’s take a look at what we’ve learned and apply it for a more realistic view of how these tools can help us.

Better PID tests

The PID tests suffered mostly from having to do a lot of extra work to patch and unpatch time.time, and had some difficulty breaking the dependence on the constructor.

Patching time.time

Using patch, we can remove a lot of the repetitiveness of dealing with time.time; this means that it’s less likely that we’ll make a mistake somewhere, and saves us from spending time on something that’s kind of boring and annoying. All of the tests can benefit from similar changes:

>>> from unittest.mock import Mock, patch
>>> with patch('time.time', Mock(side_effect = [1.0, 2.0, 3.0, 4.0,
5.0])):
... import pid
... controller = pid.PID(P = 0.5, I = 0.5, D = 0.5, setpoint = 0,
... initial = 12)
... assert controller.gains == (0.5, 0.5, 0.5)
... assert controller.setpoint == [0.0]
... assert controller.previous_time == 1.0
... assert controller.previous_error == -12.0
... assert controller.integrated_error == 0.0

Apart from using patch to handle time.time, this test has been changed. We can now use assert to check whether things are correct instead of having doctest compare the values directly. There’s hardly any difference between the two approaches, except that we can place the assert statements inside the context managed by patch.

Decoupling from the constructor

Using mock objects, we can finally separate the tests for the PID methods from the constructor, so that mistakes in the constructor cannot affect the outcome:

>>> with patch('time.time', Mock(side_effect = [2.0, 3.0, 4.0, 5.0])):
... pid = imp.reload(pid)
... mock = Mock()
... mock.gains = (0.5, 0.5, 0.5)
... mock.setpoint = [0.0]
... mock.previous_time = 1.0
... mock.previous_error = -12.0
... mock.integrated_error = 0.0
... assert pid.PID.calculate_response(mock, 6) == -3.0
... assert pid.PID.calculate_response(mock, 3) == -4.5
... assert pid.PID.calculate_response(mock, -1.5) == -0.75
... assert pid.PID.calculate_response(mock, -2.25) == -1.125

What we’ve done here is set up a mock object with the proper attributes, and pass it into calculate_response as the self-parameter. We could do this because we didn’t create a PID instance at all. Instead, we looked up the method’s function inside the class and called it directly, allowing us to pass whatever we wanted as the self-parameter instead of having Python’s automatic mechanisms handle it.

Never invoking the constructor means that we’re immune to any errors it might contain, and guarantees that the object state is exactly what we expect here in our calculate_response test.

Summary

In this article, we’ve learned about a family of objects that specialize in impersonating other classes, objects, methods, and functions. We’ve seen how to configure these objects to handle corner cases where their default behavior isn’t sufficient, and we’ve learned how to examine the activity logs that these mock objects keep, so that we can decide whether the objects are being used properly or not.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here