Design

Patching Mocks in Python

Listing Two demonstrates the creation of a MagicMock instance. Here, class Foo serves as my test resource (lines 4-9). I pass Foo as the spec argument (line 12) to the MagicMock constructor. The resulting mock (fooMock) gets the same attributes as Foo. I can access each attribute, but not the responses defined by the class (lines 14-17). I can also invoke those methods inherited from the parent Mock (lines 24, 33).

Listing Three demonstrates another way to create a MagicMock instance. Once again, I have class Foo serving as spec. But I also pass a dictionary object (fooArgs), which holds two key/value pairs (line 12). The second pair sets the return value for the Foo method doFoo(). I also pass the attribute (fooTroz), assigning it the string value of "zort.troz".

As expected, fooMock still has the same attributes as Foo (lines 15-18). But invoking doFoo() returns the string value "zort.zort", the same value set by fooArgs. Also, fooMock gains two extra properties fooNarf and fooTroz (lines 36-37); the former is defined by fooArgs as well.

Using the Decorators

A patch is temporary by design. It attaches to the target resource before the start of a test, then "disappears" at the end of the test. Figure 2 describes the lifecycle of a typical patch. Here, we have our test resource (green) and test subject (grey). The patch decorator (orange) takes hold of the resource and applies the patch (red) onto it. When the test subject interacts with the patched resource, its interactions passes through the patch. The interaction ends, and the patch "peels" itself off the test resource.

Figure 2.

There are three ways to apply a patch. One way is to have the decorator create a patcher object. Then call the patcher's start() and stop() methods to set the patching scope. Listing Four demonstrates the patcher in action. Here, class Foo is my target (lines 4-9). In it are two methods doFoo() and callFoo(). The callFoo() method gets one input argument (anArg). Class Foo also has the property myFoo, which holds a string value.

I pass class Foo to the core decorator (line 12). The decorator returns a patcher object (fooPatch), from which I invoke the start() method (line 15). In turn, fooPatch returns a MagicMock object (mockFoo), with attributes coming from class Foo. I could access each attribute, change the return value for doFoo(), and use mockFoo as I see fit (lines 18-33).

Things get interesting, however, after I invoke the stop() method (line 45). First, mockFoo remains valid. Its doFoo() method kept the return value defined within the patching zone. Class Foo is also unaffected. If I create a Foo instance (testFoo) and invoke its doFoo() method, I get the encoded value for that method (lines 48-49).

A second way to apply a patch is by context. This requires the use of a with-block, a standard feature found in Python 2.5 and newer. On Python 2.4, however, you have to import the with keyword by adding the following statement:

from __future__ import with_statement

Make sure this statement import is the first line in the script, right after the #! line (if there is one). Otherwise, the interpreter will raise a SyntaxError.

Listing Five demonstrates the use of the with-block. Class Foo is again my target. I invoke the core decorator (line 10) using the keyword with, and the decorator returns the patched resource as a MagicMock instance (mockFoo). I can access each attribute in mockFoo, set the return value for doFoo(), and do whatever I want to do with the mock (lines 12-24). Outside the with-block, mockFoo is still valid, and its doFoo() method still has the return value set within the block (line 39-40).

A third approach to patching is to apply it by method. The decorator call is right before the test routine. The decorator's name gets an @ prefix; the routine gets a mock object as one of its arguments.

Listing Six demonstrates how this is done. Routine testFoo() serves as my test routine. Before it, you'll see that the core decorator, marked with an @ prefix. And mockFoo is the sole argument for testFoo() (lines 9-26).

Here again, I get a MagicMock instance, whose attributes are from class Foo (lines 11-14). I can access the attributes, change one or more return values, and use the mock object appropriately. Outside the scope of testFoo(), however, mockFoo ceases to be valid. Attempts to use mockFoo will raise a NameError (line 41).

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.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!