1. Overview

When representing a number with a precise decimal value in Scala, we can use the BigDecimal class. This offers us a 128-bit floating-point representation of numbers, which will be more than enough for most cases.

However, suppose we find ourselves in a situation where we have to use a Double due to some legacy code in our application or the use of a library that returns Doubles. In that case, this can cause issues in writing tests for our code, as Doubles are only a 64-bit floating point number, meaning there could be precision issues when asserting values in our tests. In this article, we’ll explore how to work around this problem and reliably test functions that return a Double value within our Scala code.

2. Using Equality[Double]

The simplest solution to this issue within tests is to provide an Equality[Double] to our assertion statements. The Equality can be set to whatever value is required to tolerate the assertion. For example, providing a tolerance of 0.1 would then assert 1.1 and 1.2 as being equal, and the test would pass:

assert(1.1 === 1.2 +- 0.1)

It’s essential to provide the smallest tolerance possible when setting this value. Otherwise, an actual bug within the calculations of our code could result in a passed test due to the tolerance being too high.

2.1. Given Implicitly

One way of doing this is by providing an Equality[Double] implicitly. This can be done by calling TolerantNumerics.tolerantDoubleEquality with the desired tolerance:

implicit val doubleEquality = TolerantNumerics.tolerantDoubleEquality(0.001)
assert(100.123 === 100.122)

The benefit of doing this is that if we set it within the implicit scope of all our tests, it’ll apply to all the assertions within the test suite.

2.1. Given Explicitly

If we require more control over the tolerance of each assertion, whether that means we only want a tolerance set for specific tests or need a different tolerance for each assertion. We can use +- within the call to assert:

assert(doubleToTest === 100.122 +- 0.001)

This does the same as the implicit use. However, we’re providing the tolerance value explicitly within the assertion, which gives us more control for each test.

3. Conclusion

In this article, we have learned how to use Equality in our test cases to assist in reliability testing Double values with our Scala application code. We’ve seen the implicit and explicit ways of achieving this and know when it’s appropriate for us. Finally, we’ve discussed the risks of setting tolerance values too high and know to set them as low as reasonably possible.

As always, the sample code used in this article is available over on GitHub.