pytest: assert almost equal
Question:
How to do assert almost equal
with pytest
for floats without resorting to something like:
assert x - 0.00001 <= y <= x + 0.00001
More specifically it will be useful to know a neat solution for quickly comparing pairs of float, without unpacking them:
assert (1.32, 2.4) == i_return_tuple_of_two_floats()
Answers:
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.
Something like
assert round(x-y, 5) == 0
That is what unittest does
For the second part
assert all(round(x-y, 5) == 0 for x,y in zip((1.32, 2.4), i_return_tuple_of_two_floats()))
Probably better to wrap that in a function
def tuples_of_floats_are_almost_equal(X, Y):
return all(round(x-y, 5) == 0 for x,y in zip(X, Y))
assert tuples_of_floats_are_almost_equal((1.32, 2.4), i_return_tuple_of_two_floats())
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))
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
I’d use nose.tools. It plays well with py.test runner and have other equally useful asserts – assert_dict_equal(), assert_list_equal(), etc.
from nose.tools import assert_almost_equals
assert_almost_equals(x, y, places=7) #default is 7
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
If you want something that works not only with floats but for example Decimals you can use python’s math.isclose():
# - rel_tol=0.01` is 1% difference tolerance.
assert math.isclose(actual_value, expected_value, rel_tol=0.01)
Could just use round()
a, b = i_return_tuple_of_two_floats()
assert (1.32, 2.4) == round(a,2), round(b,1)
How to do assert almost equal
with pytest
for floats without resorting to something like:
assert x - 0.00001 <= y <= x + 0.00001
More specifically it will be useful to know a neat solution for quickly comparing pairs of float, without unpacking them:
assert (1.32, 2.4) == i_return_tuple_of_two_floats()
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.
Something like
assert round(x-y, 5) == 0
That is what unittest does
For the second part
assert all(round(x-y, 5) == 0 for x,y in zip((1.32, 2.4), i_return_tuple_of_two_floats()))
Probably better to wrap that in a function
def tuples_of_floats_are_almost_equal(X, Y):
return all(round(x-y, 5) == 0 for x,y in zip(X, Y))
assert tuples_of_floats_are_almost_equal((1.32, 2.4), i_return_tuple_of_two_floats())
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))
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
I’d use nose.tools. It plays well with py.test runner and have other equally useful asserts – assert_dict_equal(), assert_list_equal(), etc.
from nose.tools import assert_almost_equals
assert_almost_equals(x, y, places=7) #default is 7
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
If you want something that works not only with floats but for example Decimals you can use python’s math.isclose():
# - rel_tol=0.01` is 1% difference tolerance.
assert math.isclose(actual_value, expected_value, rel_tol=0.01)
Could just use round()
a, b = i_return_tuple_of_two_floats()
assert (1.32, 2.4) == round(a,2), round(b,1)