pytest:断言几乎相等

问题:pytest:断言几乎相等

如何assert almost equal使用py.test处理浮点数而不求助于以下内容:

assert x - 0.00001 <= y <= x + 0.00001

更具体地说,了解一种精巧的解决方案以快速比较浮点对而不用拆开它们将很有用:

assert (1.32, 2.4) == i_return_tuple_of_two_floats()

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

回答 0

我注意到这个问题专门询问了py.test。py.test 3.0包含一个approx()功能(很好,实际上是类),为此非常有用。

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

该文档位于此处:https : //docs.pytest.org/en/latest/reference.html#pytest-approx

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: https://docs.pytest.org/en/latest/reference.html#pytest-approx


回答 1

您将必须为您指定“几乎”是什么:

assert abs(x-y) < 0.0001

适用于元组(或任何序列):

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

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

回答 2

如果您可以访问NumPy,则它具有出色的浮点比较功能,已经可以与进行成对比较numpy.testing

然后,您可以执行以下操作:

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

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

回答 3

就像是

assert round(x-y, 5) == 0

这就是单元测试

对于第二部分

assert all(round(x-y, 5) == 0 for x,y in zip((1.32, 2.4), i_return_tuple_of_two_floats()))

将其包装在函数中可能更好

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

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

回答 4

这些答案已经存在很长时间了,但是我认为最简单,也最易读的方法是使用unittest来处理很多不错的断言,而不将其用于测试结构。

获取断言,忽略其余的unittest.TestCase

(基于此答案

import unittest

assertions = unittest.TestCase('__init__')

做出一些断言

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

实施原始问题的自动拆箱测试

只需使用*即可解包您的返回值,而无需引入新名称。

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

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

回答 5

如果您希望某些东西不仅适用于浮点数,还可以使用小数,例如可以使用python’s math.isclose

    # - rel_tol=0.01` is 1% difference tolerance.
    assert math.isclose(actual_value, expected_value, rel_tol=0.01)

文件-https: //docs.python.org/3/library/math.html#math.isclose

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)

Docs – https://docs.python.org/3/library/math.html#math.isclose


回答 6

我会用鼻子工具。它可以与py.test运行程序一起很好地运行,并具有其他同样有用的断言-assert_dict_equal(),assert_list_equal()等。

from nose.tools import assert_almost_equals
assert_almost_equals(x, y, places=7) #default is 7 

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