The Python Oracle

pytest: assert almost equal

Become part of the top 3% of the developers by applying to Toptal https://topt.al/25cXVn

--

Music by Eric Matyas
https://www.soundimage.org
Track title: Ominous Technology Looping

--

Chapters
00:00 Question
00:30 Accepted answer (Score 461)
00:56 Answer 2 (Score 53)
01:49 Answer 3 (Score 40)
02:10 Answer 4 (Score 19)
03:04 Thank you

--

Full question
https://stackoverflow.com/questions/8560...

Accepted answer links:
[approx()]: https://docs.pytest.org/en/latest/refere...

Answer 2 links:
[pytest.approx]: https://docs.pytest.org/en/latest/refere...
[pytest v3.0.0]: https://docs.pytest.org/en/7.1.x/changel...
[this]: https://stackoverflow.com/a/39623614/249...

Answer 3 links:
[numpy.testing]: https://docs.scipy.org/doc/numpy/referen...

Answer 4 links:
[many nice assertions]: https://docs.python.org/3.5/library/unit...
[this answer]: https://stackoverflow.com/a/18084492/377...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #unittesting #pytest #assert

#avk47



ACCEPTED ANSWER

Score 530


I noticed that this question specifically asked about pytest. pytest 3.0 includes an approx() function (well, really class) that is very useful for this purpose.

import pytest

assert 2.2 == pytest.approx(2.3)
# fails, default is ± 2.3e-06
assert 2.2 == pytest.approx(2.3, 0.1)
# passes

# also works the other way, in case you were worried:
assert pytest.approx(2.3, 0.1) == 2.2
# passes



ANSWER 2

Score 60


You will have to specify what is "almost" for you:

assert abs(x-y) < 0.0001

to apply to tuples (or any sequence):

def almost_equal(x,y,threshold=0.0001):
  return abs(x-y) < threshold

assert all(map(almost_equal, zip((1.32, 2.4), i_return_tuple_of_two_floats())

Update:
pytest.approx was released as part of pytest v3.0.0 in 2016.
This answer predates it, use this if:

  • you don't have a recent version of pytest AND
  • you understand floating point precision and it's impact to your use case.

for practically all common scenarios, use pytest.approx as suggested in this answer.




ANSWER 3

Score 41


If you have access to NumPy it has great functions for floating point comparison that already do pairwise comparison with numpy.testing.

Then you can do something like:

numpy.testing.assert_allclose(i_return_tuple_of_two_floats(), (1.32, 2.4))



ANSWER 4

Score 22


These answers have been around for a long time, but I think the easiest and also most readable way is to use unittest for it's many nice assertions without using it for the testing structure.

Get assertions, ignore rest of unittest.TestCase

(based on this answer)

import unittest

assertions = unittest.TestCase('__init__')

Make some assertions

x = 0.00000001
assertions.assertAlmostEqual(x, 0)  # pass
assertions.assertEqual(x, 0)  # fail
# AssertionError: 1e-08 != 0

Implement original questions' auto-unpacking test

Just use * to unpack your return value without needing to introduce new names.

i_return_tuple_of_two_floats = lambda: (1.32, 2.4)
assertions.assertAlmostEqual(*i_return_tuple_of_two_floats())  # fail
# AssertionError: 1.32 != 2.4 within 7 places