pytest:断言几乎相等


145

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

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

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

assert (1.32, 2.4) == i_return_tuple_of_two_floats()

3
py.test现在具有执行此操作的功能。
dbn

这个答案该功能的描述
汤姆·黑尔

Answers:


232

我注意到这个问题专门询问了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


12
真好!还发现它也适用于数字序列,例如assert [0.1 + 0.2, 0.2 + 0.4] == pytest.approx([0.3, 0.6])
Kriss先生

4
@Kriss先生,甚至是字典:assert {'a': 0.1+0.2} == pytest.approx({'a': 0.3})
Antony Hatchkins '17

4
这不适用于列表列表:例如,assert [[0.1 + 0.2], [0.2 + 0.4]] == pytest.approx([[0.3], [0.6]])导致TypeError。如果发现Numpy的np.testing.assert_allclose([[0.1 + 0.2], [0.2 + 0.4]], [[0.3], [0.6]])(请参见下面的答案)在这种情况下有效。
Kurt Peek

43

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

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

3
问题询问如何“不诉诸于此”如何做
endolith

我将“类似这样的东西”解释为一个重复且尴尬的表达,例如x - d <= y <= x+d,这似乎也是OP的意思。如果您不想明确指定“几乎”的阈值,请参阅@jiffyclub的答案。
yurib

2
py.test现在具有执行此操作的功能。我已经添加了讨论的答案。
dbn

2
@NeilG为什么这应该删除?如果有明显的问题,请解释它是什么。
user2699

1
@ user2699问题是如何在pytest中执行此操作。在pytest中执行此操作的正确方法是使用pytest.approx。编写自己的近似函数不是一个好主意。(此答案中的一个甚至不包括所包含的一个。)
Neil G

31

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

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

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

11

就像是

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

11

这些答案已经存在很长时间了,但是我认为最简单,也最易读的方法是使用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

6

如果您希望某些东西不仅适用于浮点数,还可以使用小数,例如可以使用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


在某些情况下,例如科学的,相对公差(或百分比差异)很方便使用。
卡里奥基

3

我会用鼻子工具。它可以与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 

2
除了pytest对此有一个选择,我不认为一个好的选择只是为此增加额外的依赖(在这种情况下,整个测试框架)。
MarcTudurí17年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.