Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# NUnit unit test not using correct method return to compare

I have the following class

public static class MyClass
{
    public static double Converter(int mpg)
    {
       return Math.Round((double)mpg / ((double)36 / 12.74), 2);
    }
}

And NUnit unit test

[TestFixture]
public class ConverterTests
{
    [Test]
    public void Basic_Tests()
        Assert.AreEqual(8.50, MyClass.Converter(24));
    }
}

My Unit tests fails with

Expected: 8.5d
But was:  8.4900000000000002d

When I debug the method return 8.49 so where does the unit test get the long number from with a 2 at the end?

like image 491
dfmetro Avatar asked Oct 20 '22 03:10

dfmetro


2 Answers

The unit test shows the same result as I see when executing the code. Here's a short but complete program to show the exact result retrieved, using my DoubleConverter class.

using System;

class Test
{
    static void Main()
    {
        double x = Convert(24);
        Console.WriteLine(DoubleConverter.ToExactString(x));
    }

    static double Convert(int mpg)
    {
        return Math.Round((double) mpg / ((double) 36 / 12.74), 2);
    }
}

Result:

8.4900000000000002131628207280300557613372802734375

Using a calculator, I'd expect the unrounded result to be 8.4933333 - which would indeed round to "about 8.49" when rounded to two decimal places.

So really, the question is more why you're seeing 8.5 in the debugger than why the unit test fails. I'm not seeing that myself, so you might want to look into exactly how you're debugging. When you debug, you may be seeing different results because:

  • In debug you may be using different floating point operations, e.g. "pure" 64-bit instead of the 80-bit intermediate operations which are permitted by .NET
  • You may be debugging other code which sets the floating point mode of the processor to 32-bit; I've seen this happen when using DirectX, but I'd expect you to be aware that you're doing it
  • The debugger may be displaying the results in a truncated form, although I wouldn't expect it to truncate that number to 8.5
like image 167
Jon Skeet Avatar answered Nov 15 '22 06:11

Jon Skeet


'double' is a dirty trick to manipulate fractions... :-)

You should NEVER test for equality when talking about doubles.

The correct way to test is:

Math.Abs(8.50 - MyClass.Converter(24)) < TOLERANCE

Where 'TOLERANCE' is how much variance is accepted.

Ex.

for TOLERANCE == 0.001
8.5004 == 8.50
8.4995 == 8.50

for TOLERANCE == 0.01
8.504 == 8.50
8.495 == 8.50
like image 38
Caverna Avatar answered Nov 15 '22 04:11

Caverna