About

That's what Mocker is about:

Graceful platform for test doubles in Python (mocks, stubs, fakes, and dummies).

Inspiration from real needs, and also from pmock, jmock, pymock, easymock, etc.

Expectation of expressions defined by actually using mock objects.

Expressions may be replayed in any order by default,

Trivial specification of ordering between expressions when wanted.

Nice parameter matching for defining expectations on method calls.

Good error messages when expectations are broken.

Mocking of many kinds of expressions (getting/setting/deleting attributes, calling, iteration, containment, etc)

Graceful handling of nested expressions (e.g. person.details.get_phone().get_prefix())

Mock proxies, which allow passing through to the real object on specified expressions (e.g. useful with os.path.isfile()).

Mocking via temporary patching of existent classes and instances.

Trivial mocking of any external module (e.g. time.time()) via proxy replacement.

Mock objects may have method calls checked for conformance with real class/instance to prevent API divergence.

Type simulation for using mocks while still performing certain type-checking operations.

Nice (optional) integration with unittest.TestCase, including additional assertions (e.g. assertIs, assertIn, etc).

Code 100% covered by tests through TDD and statement analysis (good for a testing tool)

More ...

Recent changes

Please check the NEWS file.

Supported Python versions

The following Python versions are supported by the current version of Mocker:

2.6

2.5

2.4

Download

You can find released files at:

License

Mocker is available under the BSD license (have fun!).

Bug tracking

Performed in Launchpad:

Development

Development of Mocker may be tracked in Launchpad:

The source code may be obtained using Bazaar:

bzr branch lp:mocker

Code may be browsed at:

Author

Gustavo Niemeyer <gustavo@niemeyer.net>

Tutorial

Basis

A Mocker instance is used to command recording and replaying of expectations on any number of mock objects.

Expectations should be expressed for the mock object while in record mode (the initial one) by using the mock object itself, and using the mocker (and/or expect() as a helper) to define additional behavior for each expression. For instance:

1 >> > mocker = Mocker ( ) 2 >> > obj = mocker . mock ( ) 3 4 >> > obj . hello ( ) 5 >> > mocker . result ( "Hi!" ) 6 7 >> > mocker . replay ( ) 8 9 >> > obj . hello ( ) 10 'Hi!' 11 12 >> > obj . bye ( ) 13 Traceback ( most recent call last ) : 14 . . . 15 mocker . MatchError : [ Mocker ] Unexpected expression : obj . bye 16 17 >> > mocker . restore ( ) 18 >> > mocker . verify ( )

In this short excerpt a mock object is being created, then an expectation of a call to the hello() method was recorded, and when called the method should return the value "Hi!". Then, the mocker is put in replay mode, and the expectation is satisfied by calling the hello() method, which indeed returns "Hi!". Calling the unexpected method bye() on the mock raises an error. Finally, a call to the restore() method is performed to undo any needed changes made in the environment, and the verify() method is called to ensure that all defined expectations were met.

The same kind of logic may be expressed more elegantly using the with mocker: statement (Python 2.5+), as follows:

1 >> > obj = mocker . mock ( ) 2 3 >> > obj . hello ( ) 4 >> > mocker . result ( "Hi!" ) 5 6 >> > with mocker : 7 . . . obj . hello ( ) 8 'Hi!'

Also, the MockerTestCase class, which integrates the mocker on a unittest.TestCase subclass, may be used to reduce the overhead of controlling the mocker. A test could be written as follows:

1 >> > class SampleTest ( MockerTestCase ) : 2 . . . 3 . . . def test_hello ( self ) : 4 . . . obj = self . mocker . mock ( ) 5 . . . obj . hello ( ) 6 . . . self . mocker . result ( "Hi!" ) 7 . . . self . mocker . replay ( ) 8 . . . self . assertEquals ( obj . hello ( ) , "Hi!" )

After each test method is run, expectations defined will be verified, and any requested changes made to the environment will be restored.

Expression kinds

The following expression kinds are currently understood by Mocker, and will be properly recorded if used on a mock object:

value = mock.attr

mock.attr = value

del mock.attr

mock([*args, **kwargs])

value in mock

mock[key]

mock[key] = value

del mock[key]

len(mock)

bool(mock)

iter(mock)

Notice that these expressions may be nested. For instance, notice how the following expressions are recorded and replayed back:

1 >> > obj = mocker . mock ( ) 2 >> > len ( obj . attr . method ( "param" ) ) 3 >> > mocker . result ( 3 ) 4 5 >> > mocker . replay ( ) 6 7 >> > method = obj . attr . method 8 >> > result = method ( "param" ) 9 >> > len ( result ) 10 3

Expression reactions

Mocker may instruct mock objects to react in certain ways once recorded expressions are seen during replay mode. There are two different ways to specify that, and they are completely equivalent. One of them is using method calls on the mocker instance itself, and the other is using the expect() helper. As an example:

>>> obj1 = mocker.mock() >>> obj1.hello() >>> mocker.result("Hi!") >>> obj2 = mocker.mock() >>> expect(obj2.hello()).result("Hi!")

The following reactions are supported:

result(value) - Make the last recorded expression return the given value on replay.

generate(sequence) - Last recorded expression will return a generator with the given sequence.

throw(exception) - Make the last recorded expression raise the given exception on replay

call(func, with_object=False) - Make the last recorded expression cause the given function to be called (result of function is also the result of the expression). If with_object is True, the called function will receive the patched or proxied object so that its state may be used or verified in checks.

count(min[, max]) - Last recorded expression must be replayed between min and max times (max=min, if max isn't given, and max may be None, in which case there's no upper limit).

passthrough([result_callback]) - Make the last recorded expression run on the real object once seen (works with proxies, patches, and replacements). If result_callback is given, it will be called with the value returned by the real method as the only argument.

Check the API documentation for a more detailed explanation of these methods.

Parameter matching

Mocker offers a very flexible way to match parameters in method calls.

In simple cases, parameters are matched using basic equality. For instance:

1 >> > obj = mocker . mock ( ) 2 3 >> > obj . hello ( "Joe" ) 4 >> > mocker . result ( "Hi Joe!" ) 5 6 >> > obj . hello ( "Jeff" ) 7 >> > mocker . result ( "Hi Jeff!" )

In more interesting cases, a few special parameters may be used to define the expectation.

1 >> > obj = mocker . mock ( ) 2 3 >> > obj . hello ( "Joe" , "morning" ) 4 >> > mocker . result ( "Good morning, Joe!" ) 5 6 >> > obj . hello ( "Jeff" , ANY ) 7 >> > mocker . call ( lambda name , when : "Good %s, Jeff!" % when )

It's possible to specify keyword arguments in a similar way, and also to match a variable number of positional or keyword arguments using the ARGS and KWARGS special parameters, respectively. These may be used alone or alongside other normal parameters.

As an example, the following code will record an expression which will match any method calls that take "Joe" as the second argument.

1 >> > obj = mocker . mock ( ) 2 >> > obj . hello ( ANY , "Joe" , ARGS , KWARGS )

The following special parameters are available:

ANY - Matches any single parameter (positional or keyword, depending on the context used).

ARGS - Matches any number of postional parameters, in the position where it was used.

KWARGS - Matches any number of keyword arguments.

IS(object) - Matches parameter if it is the given object.

IN(object) - Matches parameter if it is contained in the given object.

CONTAINS(object) - Matches parameter if it contains the given object.

MATCH(func) - Matches parameter if func(param) is true.

Patching limitations:

At this time patching doesn't work in classmethods.

Ordering of expressions

By default, mocker won't force expressions to be expected precisely in the order they were recorded. You can change this behavior in a few different ways. Which one is used in a given occasion depends only on convenience.

One way to obtain ordering is calling mocker.order(). With this, the mocker will be put in a mode where any recorded expressions following it will only be met if they are replayed in the recorded order. When that's used, the mocker may be put back in unordered mode by calling mocker.unorder(), or by using a with mocker.order(): block, like so:

1 >> > with mocker . order ( ) : 2 . . . obj . hello ( ) 3 . . . mocker . result ( "Hi!" ) 4 . . . 5 . . . obj . bye ( ) 6 . . . mocker . result ( "See ya!" ) 7 8 >> > 9 10 >> > mocker . replay ( ) 11 12 >> > obj . bye ( ) 13 Traceback ( most recent call last ) : 14 . . . 15 mocker . MatchError : [ Mocker ] Unexpected expression : obj . bye 16 17 >> > obj . hello ( ) 18 'Hi!' 19 >> > obj . bye ( ) 20 'See ya!'

Note how the first call to bye() raises an error, because hello() hadn't been called yet.

Proxying

Two powerful features of Mocker which aren't commonly seen in other mocking systems is the ability of proxying to existing objects, or even patching the real instance or class.

When an object is proxied, Mocker will create a mock object which will hold a reference to the real object, and will allow expressions to passthrough (mocked or not, and by default or on request).

To understand how it works in practice, let's define a new class:

1 >> > class Greeting ( object ) : 2 . . . 3 . . . def hello ( self , name ) : 4 . . . return "Hi %s!" % name 5 . . . 6 . . . def bye ( self ) : 7 . . . return "See ya!"

Let's see an example:

1 >> > greeting = Greeting ( ) 2 3 >> > obj = mocker . proxy ( greeting ) 4 >> > obj . hello ( "Jeff" ) 5 >> > mocker . result ( "Hello buddy!" ) 6 7 >> > obj . hello ( "Jim" ) 8 >> > mocker . passthrough ( ) 9 10 >> > mocker . replay ( ) 11 12 >> > obj . hello ( "Jim" ) 13 'Hi Jim!' 14 15 >> > obj . hello ( "Jeff" ) 16 'Hello buddy!' 17 18 >> > obj . hello ( "Joe" ) 19 'Hi Joe!' 20 21 >> > obj . hello ( "Jim" ) 22 Traceback ( most recent call last ) : 23 . . . 24 AssertionError : [ Mocker ] Unmet expectation : 25 26 = > obj . hello ( 'Jim' ) 27 - Performed more times than expected .

Note how we requested that one call taking "Jeff" as an argument should result in a message with Hello, and that a single call taking "Jim" as an argument should be made, and it should passthrough to the real object. Then, when replaying, we've used both of them, and then a third call which uses neither was made, and it passed through (that's the default setting, see the patch() method documentation for more details). Also interestingly, a second call with the "Jim" argument failed, because we said it'd happen only once (mocker.count() could have changed this).

Mocker also offers a proxy and replace mode, which basically means that if using the replace() method instead of proxy(), on replay time the returned mock object will replace the original object in namespaces of the whole Python interpreter (including modules, etc). Using that system, it's trivial to perform environment-level changes, such as in functions defined in standard Python modules. Both replace() and proxy() offer a mode where the passed object may be an "import string" instead of an object, to facilitate that kind of operation even more. Here is a simple example to illustrate how it may be used (luckily examples are still simple even when the explanation isn't):

1 >> > obj = mocker . replace ( "time.time" ) 2 >> > obj ( ) 3 >> > mocker . result ( 123 ) 4 5 >> > mocker . replay ( ) 6 7 >> > from time import time 8 >> > time ( ) 9 123

Note that this works even if modules have already run "from time import time" by the time mocker is instructed to perform the replacement.

As explained in the Basis section, changes will be undone when the mocker is restored.

Patching

Being able to patch objects is another powerful and uncommon feature found in Mocker, which is certainly handy in certain occasions.

When an object is patched, Mocker will return a mock object as usual, and will allow expectations to be defined on it. But then, when put on replay mode, Mocker will make modifications so that the real class or instance acts as defined by the recorded expectations. Just like with proxies, Mocker will allow expressions to passthrough to the real implementation when desired. Once the Mocker is restored (by calling mocker.restore() explicitly, or by the end of a with block, or by returning from a test method in MockerTestCase), Mocker will ensure that the patched object is put back in its original form.

Let's define the same Greeting class again, just for proximity with the following examples.

1 >> > class Greeting ( object ) : 2 . . . 3 . . . def hello ( self , name ) : 4 . . . return "Hi %s!" % name

Patching works both in classes and in instances. When a class is patched, all instances of this class will act and be restricted by defined expectations, while if defined in the instance itself, only the given instance will reflect these.

Here is a simple example of changes performed for an instance:

1 >> > greeting = Greeting ( ) 2 >> > obj = mocker . patch ( greeting ) 3 4 >> > obj . hello ( "Jeff" ) 5 < mocker . Mock object at 0xb76c608c > 6 >> > mocker . result ( "Hello Jeff!" ) 7 8 >> > mocker . replay ( ) 9 10 >> > greeting . hello ( "Jeff" ) 11 'Hello Jeff!' 12 >> > greeting . hello ( "Joe" ) 13 'Hi Joe!' 14 15 >> > type ( greeting ) 16 < class '__main__.Greeting' > 17 18 >> > mocker . restore ( ) 19 >> > greeting . hello ( "Jeff" ) 20 'Hi Jeff!'

As explained in the Basis section, changes are fully undone when the mocker is restored.

Mocked expressions may easily passthrough to the real object, using the mocker.passthrough() method, as previously explained.

Specification checking for API conformance

One issue with using mock objects is that, depending on the amount of integration test performed, real objects may diverge from the mocked objects, and this might go unnoticed for a while. Mocker tries to minimize that situation by allowing method calls to be checked for conformance against the real object. These checks may be easily enabled for pure mock objects, and are performed by default with proxies and patched objects (it's possible to disable these; see the API documentation for more information).

Here is an example:

1 >> > class Greeting ( object ) : 2 . . . 3 . . . def hello ( self , name ) : 4 . . . return "Hi %s!" % name 5 6 7 >> > obj = mocker . mock ( Greeting ) 8 >> > obj . hello ( "Joe" , "what?" ) 9 10 >> > mocker . replay ( ) 11 12 >> > obj . hello ( "Joe" , "what?" ) 13 Traceback ( most recent call last ) : 14 . . . 15 AssertionError : [ Mocker ] Unmet expectation : 16 17 = > obj . hello ( 'Joe' , 'what?' ) 18 - Specification is hello ( name ) : too many args provided

Notice that passing the spec as the first parameter of the mock() method will also enable the type simulation, as explained in the next section. To perform just specification checking, use the spec keyword argument explicitly.

To disable specification checking for a specific expression, Mocker offers the nospec() method. It's also possible to disable these checks on proxies and patched objects using spec=None when buildling these.

Type simulation

It's possible to ask Mocker to lie when its _ _class_ _ attribute is accessed. This makes it easier to perform type-related checks in the implementation while still using mock objects.

This is enabled by default on proxies, and may be easily requested with pure mock objects, as follows:

1 >> > obj = mocker . mock ( Greeting ) 2 3 >> > mocker . replay ( ) 4 5 >> > obj . __class__ 6 < class '__main__.Greeting' > 7 8 >> > isinstance ( obj , Greeting ) 9 True 10 11 >> > type ( obj ) 12 < class 'mocker.Mock' >

Note how type() will still reveal the truth. Also, the first argument to mock() will enable specification checking (see previous section). Use the type keyword argument if you really want just type simulation.

Extension to unittest.TestCase

Mocker offers MockerTestCase, which is a handy subclass of unittest.TestCase integrating Mocker support. It's by no means required for using what Mocker offers, but even then it's definitely a convenient integration.

Test methods will have a Mocker instance available on self.mocker, and at the end of each test method, expectations of the mocker will be verified, and any requested changes made to the environment will be restored, without any manual intervention.

It also offers self.expect, which is an alias for the expect() helper.

Tests which don't require the mocker will not be affected.

Here is a short example:

1 >> > class SampleTest ( MockerTestCase ) : 2 . . . 3 . . . def test_hello ( self ) : 4 . . . obj = self . mocker . mock ( ) 5 . . . obj . hello ( ) 6 . . . self . mocker . result ( "Hi!" ) 7 . . . self . mocker . replay ( ) 8 . . . self . assertEquals ( obj . hello ( ) , "Hi!" )

In addition to the integration with Mocker, this class provides a few additional helper methods, which make it interesting even when Mocker itself isn't needed.

assertIs(first, second) - Asserts that first is the same object as second.

assertIsInstance(obj, cls) - Asserts that obj is an instance of cls.

assertIn(first, second) - Asserts that first is contained in second.

assertStartsWith(first, second) - Asserts that first starts with second.

assertEndsWith(first, second) - Asserts that first ends with second.

assertApproximates(first, second, tolerance) - Asserts that first is near second by at most the given tolerance.

assertMethodsMatch(first, second) - Asserts that methods of class first exist in class second, and take precisely the same arguments.

makeFile(content=None, suffix="", prefix="tmp", basename=None, dirname=None, path=None) - Creates a file (if content is not None) with the given information and returns its filename. The file is removed after the test method returns.

makeDir(suffix="", prefix="tmp", dirname=None, path=None) - Creates a temporary directory and returns its name. The directory and its contents are removed after the test method returns.

addCleanup(func, *args, **kwargs) - After the test method is finished, ensure that func(*args, **args) is called.

In addition to these, the following extensions to standard modules were made:

assertRaises(exc, func=None, *args, **kwargs) - In addition to the standard features, this method returns the raised exception so that further tests on it may be done. Also, it supports the Python 2.7/3.2 use of assertRaises() with a single argument, so that it can be used as: with self.assertRaises(MyException): raising_logic()

assertRaisesRegexp(exc, regexp, func=None, *args, **kwargs) - Works very similarly to assertRaises(), but will also ensure that str(error) matches the provided regular expression.

All of the expected negations and aliases for these methods are also available (note that one of them is spelled assertIsNot, rather than assertNotIs, for obvious reasons).

Credits for the assertApproximates() idea go to Twisted's Trial.