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.
Figure 1.
Table 1 lists some of those magic methods and their intended responses.
Magic Method | Default Response |
|
|
|
|
|
|
|
|
|
|
|
|
__hash__ |
|
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.