Search code examples
c#unit-testingvisual-studio-2015intellitest

How do I use Intellitest to test floating point output?


I'm fairly new to Intellitest in VS 2015 (and unit tests in general), and I'm trying to use it to test a simple method that converts between inches and mm.

I understand that Intellitest has limitations around floating point tests. How do I work around these, ideally without stepping completely outside the framework? I'm using it successfully for the rest of the code, so I'd like to find a workaround that matches the same approach as much as possible.

I have two properties on a class:

public double CutLengthInInches
{
    get;
    set;
}

public double CutLengthInMM
{
    get
    {
        return CutLengthInInches * 25.4;
    }
    set
    {
        CutLengthInInches = value / 25.4;
    }
}

I then use Intellitest to create a stub, which I fill out as follows:

[PexMethod]
public void CutLengthInMMSet([PexAssumeUnderTest]CutPiece target, double value)
{
    target.CutLengthInMM = value;
    PexAssert.AreEqual(value, target.CutLengthInMM);
    PexAssert.AreEqual(value, target.CutLengthInInches * 25.4);
}

When I run this, Intellitest complains with an error:

The following operation was involved in a branch condition:

floating point equality

This operation causes testability problems, and inputs cannot be generated to cover the code following the call.

The line it points to is the first AreEqual() call. What's the tidiest workaround to this?


Solution

  • Your assertion is doing an exact comparison between floating point values. You should avoid such comparison regardless of whether you are using IntelliTest. It is unsafe for applications to rely on exact floating-point comparisons; slight variations in rounding can change the outcome of such comparisons, leading to unexpected behavior (for e.g. test case failures!).

    Instead, tests for equality of floating-point quantities should be made within some tolerance related to the expected precision of the calculation (i.e. compare whether the values are "equal enough").

    For e.g. if you go with double.Epsilon as your tolerance, then update the comparison like so: (Math.Abs(value - target.CutLengthInMM) < double.Epsilon).

    Now, coming to IntelliTest: When IntelliTest observes code doing such exact comparisons it flags them with the Testability warning. Continuing with above tolerance value, update your assertion as follows:

    PexAssert.IsTrue(Math.Abs(value - target.CutLengthInMM) < double.Epsilon);
    

    You will see a warning that the call to Math.Abs was uninstrumented. That is OK (since we are not interested in testing that method). After ensuring that you have addressed any other such issues, you can select the warning and Suppress it (by clicking on the Suppress button on the Exploration Results window’s toolbar).