pytest: assert almost equal

PythonUnit TestingPytest

Python Problem Overview


How to do assert almost equal with py.test 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 compare pairs of float, without unpacking them:

assert (1.32, 2.4) == i_return_tuple_of_two_floats()

Python Solutions


Solution 1 - Python

I noticed that this question specifically asked about py.test. py.test 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

The documentation is here.

Solution 2 - Python

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())

Solution 3 - Python

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))

Solution 4 - Python

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

Solution 5 - Python

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())

Solution 6 - Python

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)

Solution 7 - Python

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 

Solution 8 - Python

Could just use round()

a, b = i_return_tuple_of_two_floats()
assert (1.32, 2.4) == round(a,2), round(b,1)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVladimir KeleshevView Question on Stackoverflow
Solution 1 - PythondbnView Answer on Stackoverflow
Solution 2 - PythonyuribView Answer on Stackoverflow
Solution 3 - PythonjiffyclubView Answer on Stackoverflow
Solution 4 - PythonKobeJohnView Answer on Stackoverflow
Solution 5 - PythonJohn La RooyView Answer on Stackoverflow
Solution 6 - PythonvalidnameView Answer on Stackoverflow
Solution 7 - PythonvolodymyrView Answer on Stackoverflow
Solution 8 - PythonPlutoView Answer on Stackoverflow