[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
out.
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