Test doubles (stubs and mocks) for unit testing (was: unit testing)

Ben Finney bignose+hates-spam at benfinney.id.au
Fri Oct 5 18:51:41 EDT 2007


7stud <bbxx789_05ss at yahoo.com> writes:

> What are some strategies for unit testing a function that obtains
> user input?

This is just one example of "how do I unit test a code unit that
interacts with something complex outside itself?" You want to test
*only* the code unit under test, not the external object with which it
interacts.

The answer is: Replace the external object irrelevant to your test
with a "test double" — a stub or mock object — that exhibits the
expected behaviour to the code unit, but doesn't perform the complex
behaviour that's irrelevant to your unit test.

If it's a matter of something simple and deterministic like "the input
for this test should be 'foo'", then the test double needs to do
nothing but respond to the expected method calls by producing the test
data. This is a "stub object", and you replace the real one with this
during the setup for your test case.

In more complex cases (e.g. "the code unit should write specific data
to this file", or "the code unit should make this change to the
database"), the test double needs to respond to method calls and
produce test data as needed, but also needs to be able to assert that
the right method calls were made. An instrumented test double like
this is called a "mock object", and you can query its state during the
test to assert that it has been manipulated as expected.

More about the difference between mock objects and stub objects:

    <URL:http://martinfowler.com/articles/mocksArentStubs.html>

My favourite mock objects are created with Ian Bicking's "minimock",
which uses the doctest functionality for the instrumentation, and
keeps it really simple:

    <URL:http://blog.ianbicking.org/minimock.html>

Set up any required test doubles at the start of each test case (so
you start with a known state each time), and switch back the real one
at the end of the test case. The test double thus becomes part of the
"test fixtures" for that specific test case.

More about test doubles (stub and mock objects) with Python:

    <URL:http://pycheesecake.org/wiki/PythonTestingToolsTaxonomy>
    <URL:http://www.mockobjects.com/>

Note that this works best when the external interface is a replaceable
object, or a small number of them. If the number of things that need
to be replaced with test doubles just to perform a single test case is
high, that's a warning sign: your code unit is too tightly coupled to
too many things, and you need to refactor it soon to have a looser
interface to the rest of the system.

    <URL:http://www.c2.com/cgi/wiki?CouplingAndCohesion>

-- 
 \        "I'd take the awe of understanding over the awe of ignorance |
  `\                                       any day."  -- Douglas Adams |
_o__)                                                                  |
Ben Finney



More information about the Python-list mailing list