unittest: Proposal to add failUnlessNear

Bengt Richter bokr at oz.net
Mon Jul 19 19:34:08 CEST 2004

On 19 Jul 2004 11:06:47 GMT, Antoon Pardon <apardon at forel.vub.ac.be> wrote:

>I have been working with unittests lately and found that the
>self.failUnlessAlmostEqual, isn't as usefull as it could be.
>My main problem is, that it is only usefull with objects
>that can be converted to floats, while there are a whole
>bunch of objects that can be almost equal but not so
>convertable. The first example coming to mind being
>complex numbers.
>A secondary objection is that you are limited to
>a very specific set of tolerances. If for instance
>you want to verify that two numbers differ at most
>by 0.0003 you can't specify that.
>So I propose to add the following
>  def failUnlessNear(self, first, second, tolerance=1e-7, msg=None, norm=abs):
>      """Fail if the two objects are too far appart as determined
>         by the distance between them and the tolerance allowed.
>      """
>      if norm(second-first) > tolerance:
>          raise self.failureException, \
>                (msg or '%s != %s within %s tolerance' % (`first`, `second`, `tolerance`))
>Antoon Pardon

How about a more general solution? E.g., how about an optional keyword arg
passed to failUnlessAlmostEqual? (I'm guessing here, no time to look at it)
E.g., that way for mixed numbers including complex you could (if you thought
it made sense, which I am not necessarily arguing ;-) use e.g.

    def special_cmp(x,y): # untested!
        diff = complex(x)-complex(y)
        return max(cmp(abs(diff.real), tolerance), cmp(abs(diff.imag), tolerance))

and pass cmp=special_cmp as the kwarg.

For special objects, you could define other kinds of nearness, and raise
appropriate informative exceptions if you get non-comparable arguments.

(obviously tolerance has to be defined, so if you want to vary it conveniently,
you could pass it to a factory function that does the above def and returns
it with tolerance captured in a closure referred to by special_cmp).

Or some other way. The point is you get to define the cmp= function as you please
without modifying the framework (once the optional kwarg is implemented).)

gotta go...

Bengt Richter

More information about the Python-list mailing list