Channels ▼
RSS

Testing

Patching Mocks in Python


Sometimes, you need a resource to behave differently in a test and the change must be temporary, lest it affect other unrelated tests. To change a resource's behavior temporarily, you can employ patching, a capability built into Python's Mock module, whose workings I explained in a previous article.

In this article, I explain the mock patching mechanism and describe four types of patch decorators, then demonstrate several ways to apply a patch. I also examine the MagicMock class and explain its role in patching.

The code works with all versions of Python 2.x from v. 2.4.1 on. It also uses Mock 1.0.1.  Readers should have a good grasp of Python, the Mock class, and basic unit testing.

Reasons to Patch

Suppose you want a resource to raise an error or exception on cue. You could try changing the resource's source code itself; but this means exclusive access to the source code — not possible when the resource is a commercial product. If you do have source access, changing the source incurs overhead. You need to locate the appropriate code and figure out what changes to make. You have to rebuild the resource, fix any errors that crop up, then test to make sure your changes work as expected and and that you have not broken anything else.

A better and safer approach is to use a mock. A mock takes the place of the test resource and offers the same method interface. You can have each method return a value or raise an error/exception. And you can easily customize a mock to suit a specific test or test routine. This customization, especially, when done temporarily, is where patching comes in handy. There are many situations in which this can happen, for example, forcing an unusual condition or behavior so you can test it, without creating an entirely new mock object simply to exhibit the desired behavior.

The Patch Decorators

The Mock module uses four decorators to patch a resource. Decorators are specialized methods. They return the patched resource as a mock, a separate object, or class.

The core decorator patch is most often used. It takes several arguments, of which target argument is required.

patch(target, new = DEFAULT, spec|spec_set = None,
  new_callable = None, autospec = None, **kwArgs)

The target argument is the patch target, which can be a class or a mock. If the class is in a separate file, pass its name as package.module.ClassName. If the class is in the same file as the decorator, pass '__main__.ClassName'.

The spec and spec_set arguments sets the attributes for patching. The attributes can come from a list of names or from a class. Omitting spec and spec_set tells the core decorator to use the target's attributes.

The autospec argument is another way to supply attributes for patching. Pass an arbitrary object, and the patched resource will take on that object's attributes. Pass a True, and the patched resource takes on the target's attributes.

The new argument sets the basis for the patched resource. This can be a class, an object, or even another mock. If omitted, the decorator builds the patched resource using the MagicMock class (more about MagicMock later).

The new_callable argument also sets the class or object with which to base the patched resource. But the class/object must be callable; that is, it implements the magic method __call__(). Again, the decorator uses the MagicMock class by default.

Finally, the kwArgs argument uses a dictionary object as a source of attributes. Unlike spec, spec_set, or autospec, kwArgs also sets the initial values for each attribute. Each dictionary entry consists of the attribute name (the key) and the patch value.

The decorator patch.object is another way to create a patched resource. It shares the same optional arguments as the core decorator. The decorator expects at least two arguments.

patch.object(target, attribute, [value, ...])

The target argument is the target resource. The attribute argument is the attribute being patched. The optional value argument is the value to assign to the attribute. The other six optional arguments are the same as in the previous core decorator.

The decorator patch.dict uses a dictionary object for a target.

patch.dict(target, values = {}, [clear = False, **kwArgs])

The values argument is a sequence of key/value pairs to patch into the target. The optional argument clear resets the target, removing all its entries prior to patching. And the kwArgs argument is another dictionary, whose entries are patched into the target.

The decorator patch.multiple enables you patch several target resources at a time.

patch.multiple(target, mock1 = DEFAULT,...,mockN = DEFAULT, [spec|spec_set = None, autospec = None, new_callable = None, **kwArgs])

The target argument sets the location of the target resources. Again, if the resources are in the same file as the decorator, set this argument to "__main__". The arguments mock1 to mockN are the targets. Setting a target to DEFAULT produces a MagicMock instance, with the same attributes as the target's. Setting a target to a class produces a callable class. The patch.multiple decorator uses the same optional arguments as the core decorator, but patch.multiple applies those arguments equally to all targets.

The MagicMock class

You may have noticed that all four patch decorators can use the MagicMock class to produce the patched resource. MagicMock is a subclass of Mock. It shares the same constructor arguments as Mock, as well as the same assert and history routines. However, MagicMock provides default implementations for a handful of magic methods.

Figure 1 shows the classes that form MagicMock. The Mock class supplies the properties, methods, and asserts that MagicMock needs. It is the same class I covered in Using Mocks in Python. The MagicMixin class also defines the return values for the magic methods.

patching mocks in python
Figure 1.

Table 1 lists some of those magic methods and their intended responses.

Magic Method Default Response

__int__

1

__float__

1.0

__long__

1

__hex__

0x1

__str__

<MagicMock id='499344'>

__len__

0

__hash__

499344

Table 1.

Listing One shows some of those responses. The first five methods return the same numeric value of 1. The __str__ method returns a MagicMock instance, the __len__ method returns a 0. And the __hash__ method returns the object's unique ID (the same ID returned by __str__).

Listing One

from mock import Mock, MagicMock

# create mock object
fooMock = MagicMock()

# test magic methods
print int(fooMock)
# returns: 1
print float(fooMock)
# returns: 1.0
print oct(fooMock)
# returns: 1
print hex(fooMock)
# returns: 0x1
print long(fooMock)
#returns: 1

print str(fooMock)
#returns: <MagicMock id='499344'>
print len(fooMock)
# returns: 0
print hash(fooMock)
#returns: 499344

print fooMock == fooMock
#returns: True
print fooMock == MagicMock()
#returns: False
print fooMock != 'MagicMock'
#returns: True
print fooMock > 'MagicMock'
#returns: False
print fooMock < 'MagicMock'
#returns: True

However, other magic methods are not implemented. Methods such as__init__, __getattr__, and __setattr__ are used by the parent class Mock. You must avoid changing these methods, lest you affect the mock's behavior. Methods such as __bool__ and __next__ are not implemented because these are specific to Python 3. Similarly, methods such as __unicode__ and __nonzero__ are not implemented because they are Python 2-specific.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video