[TIP] RFF: Article on python test design pattern - DAI

Mark Sienkiewicz sienkiew at stsci.edu
Tue Dec 8 14:41:19 PST 2009

> http://redsymbol.net/articles/deep-assertion-injection/
> I am surely not the first to use this idiom, but I *might* be the first to 
> document it this well, and to give it a name.  Have you seen this before? 
> Constructive feedback is appreciated.

In many languages, the parameter "urlopen" in your example is called a 
"callback function".  I don't remember ever seeing callbacks used 
_specifically_ as a test feature, but you can certainly do that.

By (in your example) exposing urlopen in this way, you have not just 
added a cool test point.  You have also added another way that the user 
can interact with your function/object.  For example, if I need a 
different urlopen than you have provided as your default, it might be 
much easier for me to provide my own urlopen than it would be for me to 
subclass your object and start overriding bits and pieces of it.  You 
already noted this in your description, but as a test feature; I'm 
saying it could also be part of the intended interface.

At the very least, python programmers usually write poor documentation 
of their interfaces, so other python programmers have to look at the 
source code to find out how something works. They will surely notice the 
other parameter, even if you don't mention it in the docstring.

( b.t.w. A callback can be easier to use precisely because it is _not_ a 
method of the object; you know that the interface is defined solely by 
the parameters and return value, so you don't need to know about the 
attributes of the object or what they mean. )

Others have noted that exception handling inside the function might be a 
problem, but I don't think it is a big deal.  As the author, you will 
know where that exception handling is, so you know what can/can't be 
tested with an assert statement.  If there is a problem, you can use 
some other channel (e.g. globals, message queues) to get the test status 

Mark S.

p.s.  If you design your software carefully, you don't need closures or 
dynamically created functions -- all you need is function pointers, like 
you have in C.  Just write your callback function so that the only 
interface to it is through the parameters and return value.  (In 
general, that would be a good idea for Python too, just from a 
readability perspective.)

More information about the testing-in-python mailing list