unittest: Proposal to add failUnlessNear

Bengt Richter bokr at oz.net
Mon Jul 19 13:34:08 EDT 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
    cmp=comparison_function
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...

Regards,
Bengt Richter



More information about the Python-list mailing list