Joe White’s Blog

Life, .NET, and Cats


DUnitAssertions: Epsilons

You never want to do exact comparisons on floating-point numbers. They’re finite precision — and 0.1 is a nonrepeating fraction in binary. So 1.1 plus 0.1 does not necessarily equal 1.2.

So float comparisons should always have an epsilon, or fudge factor — something that says “if the difference is only 0.000001, that’s close enough”. That’s why Delphi has the SameValue function (which provides its own reasonable epsilon if you don’t specify your own), and why DUnit has overloads for CheckEquals that take an epsilon.

NUnitLite apparently doesn’t do epsilons, though, so I’m on my own for coming up with a meaningful syntax as I write DUnitAssertions. Here are a few of my brainstorms:

Expect.That(1.1 + 0.1, Tis.EqualTo(1.2, 1E-6));
Expect.That(1.1 + 0.1, Tis.EqualTo(1.2), 1E-6);
Expect.That(1.1 + 0.1, Tis.EqualTo(1.2), Tis.Within(1E-6));
Expect.That(1.1 + 0.1, Tis.EqualTo(1.2), To.Within(1E-6));
Expect.That(1.1 + 0.1, Tis.EqualTo(1.2), Plus.Minus(1E-6));
Expect.That(1.1 + 0.1, Tis.EqualTo(1.2).ToWithin(1E-6));

I like the third one (To.Within) the best, except that it won’t compile (to is a reserved word in Delphi). Obviously I could make it &To but that’s kludgy; a Delphi test framework should compile in Delphi without escaping the method names. Jennie suggested “plus or minus”, which is what prompted Plus.Minus. The last one might work too, although I’d have to fiddle with it.

I’m also not sure how discoverable any of these are. Ideally I’d want something where anyone could sit down with nothing more than the test framework, Intellisense, and one example (Expect.That(2 + 2, Is.EqualTo(4), 'Something is wrong');), and be able to figure the rest out. I already know that’s an impossible goal in Delphi/Win32, because of the issues with enums, but it’s still a decent aim.

Any preferences among these examples? Suggestions?

3 Responses to “DUnitAssertions: Epsilons”

  1. Brad White Says:

    That depends, of course.

    What are the other methods of Tis?

    What does EqualTo return?

    At first glance I would expect that EqualTo should take the epsilon. Your first example.

    But that depends on what EqualTo does.

  2. Joe White Says:

    Tis.EqualTo (and its siblings Tis.GreaterThan, Tis.Not.EqualTo, etc.) returns a constraint, which is a hybrid type (essentially an interface reference).

    Expect.That then calls methods on the constraint to decide whether the constraint matches the actual value, and if not, to generate the failure message ("Expected… but was…") and throw an exception.

    Currently I’m also leaning toward the first example, because it’s easiest from an implementation standpoint right now. But if I can think of something that’s more readable, I’ll work it in — after all, you read test code a lot more often than you write it.

  3. Ajasja Says:

    I’d go for the first or the last one.

    But that’s just a feeling (and not based on, for example, years of experience:)

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Joe White's Blog copyright © 2004-2008. Portions of the site layout use Yahoo! YUI Reset, Fonts, and Grids.
Proudly powered by WordPress. Entries (RSS) and Comments (RSS).