pytest Quick Start Guide
上QQ阅读APP看书,第一时间看更新

Comparing floating point numbers: pytest.approx

Comparing floating point numbers can be tricky. For more details, go to: https://docs.python.org/3/tutorial/floatingpoint.html. Numbers that we consider equal in the real world are not so when represented by computer hardware:

>>> 0.1 + 0.2 == 0.3
False

When writing tests, it is very common to compare the results produced by our code against what we expect as floating point values. As shown above, a simple == comparison often won't be sufficient. A common approach is to use a known tolerance instead and use abs to correctly deal with negative numbers:

def test_simple_math():
assert abs(0.1 + 0.2) - 0.3 < 0.0001

But besides being ugly and hard to understand, it is sometimes difficult to come up with a tolerance that works in most situations. The chosen tolerance of 0.0001 might work for the numbers above, but not for very large numbers or very small ones. Depending on the computation performed, you would need to find a suitable tolerance for every set of input numbers, which is tedious and error-prone.

pytest.approx solves this problem by automatically choosing a tolerance appropriate for the values involved in the expression, providing a very nice syntax to boot:

def test_approx_simple():
assert 0.1 + 0.2 == approx(0.3)

You can read the above as assert that 0.1 + 0.2 equals approximately to 0.3.

But the  approx function does not stop there; it can be used to compare:

  • Sequences of numbers:
      def test_approx_list():
assert [0.1 + 1.2, 0.2 + 0.8] == approx([1.3, 1.0])
  • Dictionary values (not keys):
      def test_approx_dict():
values = {'v1': 0.1 + 1.2, 'v2': 0.2 + 0.8}
assert values == approx(dict(v1=1.3, v2=1.0))
  • numpy arrays:
      def test_approx_numpy():
import numpy as np
values = np.array([0.1, 0.2]) + np.array([1.2, 0.8])
assert values == approx(np.array([1.3, 1.0]))

When a test fails, approx provides a nice error message displaying the values that failed and the tolerance used:

    def test_approx_simple_fail():
> assert 0.1 + 0.2 == approx(0.35)
E assert (0.1 + 0.2) == 0.35 ± 3.5e-07
E + where 0.35 ± 3.5e-07 = approx(0.35)