XCTAssertEqual not working for double values
Asked Answered
S

2

45

I am writing some unit tests for a map coordinate function that I am writing. Unfortunately, there's something going on with XCTest that I am unable to nail down that is causing my test to fail:

NSString *testValue = @"121°31'40\"E";

double returnValue = coordinateStringToDecimal(testValue);
static double expectedValue = 121.5277777777778;
XCTAssertEqual(returnValue, expectedValue, @"Expected %f, got %f", expectedValue, returnValue);

I did read this similar question to troubleshoot. However, I am able to validate that the numbers and types are the same. Here is the console output of checking the type of each value:

(lldb) print @encode(__typeof__(returnValue))
(const char [2]) $5 = "d"
(lldb) print @encode(__typeof__(expectedValue))
(const char [2]) $6 = "d"

The Variables View in the debugger is showing them to be the same:

enter image description here

The interesting thing is the console output of comparing them in lldb:

(lldb) print (returnValue == expectedValue)
(bool) $7 = false

The types are the same and the actual numbers are the same. Why else would my assert be failing???

Salivation answered 2/1, 2014 at 21:45 Comment(0)
S
97

Because you are dealing with floating point numbers, there will always be a certain degree of inaccuracy, even between double values. In these cases, you need to use a different assertion: XCTAssertEqualWithAccuracy. From the docs:

Generates a failure when a1 is not equal to a2 within + or - accuracy. This test is for scalars such as floats and doubles, where small differences could make these items not exactly equal, but works for all scalars.

Change your assert to something like this:

XCTAssertEqualWithAccuracy(returnValue, expectedValue, 0.000000001);

Or in Swift 4:

XCTAssertEqual(returnValue, expectedValue, accuracy: 0.000000001, "expected better from you")

In Nimble:

expect(expectedValue).to(beCloseTo(returnValue, within: 0.000000001))
Salivation answered 2/1, 2014 at 21:48 Comment(3)
In swift 3, an accuracy argument label was added: XCTAssertEqualWithAccuracy(returnValue, expectedValue, accuracy: 0.000000001, "expected better from you");Boleyn
It now looks like there is just an overload of XCTAssertEqual that allows an accuracy argument, just as XCTAssertEqualWithAccuracy did.Ladylike
Use .ulpOfOne instead of some static float value, which is equivalent to FLT/DBL_EPSILON.Lesbian
D
14

In Swift 4 accuracy was removed from the function name - now its an overload of XCTAssertEqual:

XCTAssertEqual(returnValue, expectedValue, accuracy: 0.000000001, "expected better from you")
Dampproof answered 2/2, 2018 at 10:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.