pytest:断言几乎相等

Vla*_*hev 114 python unit-testing pytest

如何assert almost equal处理浮动的py.test而不诉诸于:

assert x - 0.00001 <= y <= x + 0.00001
Run Code Online (Sandbox Code Playgroud)

更具体地说,知道一个简洁的解决方案来快速比较浮动对,这将是有用的,而无需解压缩它们:

assert (1.32, 2.4) == i_return_tuple_of_two_floats()
Run Code Online (Sandbox Code Playgroud)

dbn*_*dbn 189

我注意到这个问题专门询问了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
Run Code Online (Sandbox Code Playgroud)

文档在这里:https://docs.pytest.org/en/latest/reference.html#pytest-approx

  • 太好了!还发现它也适用于数字序列,例如`assert [0.1 + 0.2,0.2 + 0.4] == pytest.approx([0.3,0.6])` (9认同)
  • 值得注意的是,第二个位置参数是相对容差,但您也可以指定绝对容差: `0.2 == pytest.approx(0.3, 0.1) # returns false; 0.2 == pytest.approx(0.3, abs=0.1) # 返回 true` (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]])`(见下面的答案)确实适用于这种情况. (3认同)
  • @Mr Kriss甚至对于dicts:`assert {'a':0.1 + 0.2} == pytest.approx({'a':0.3}) (2认同)

yur*_*rib 41

您必须为您指定"几乎"的内容:

assert abs(x-y) < 0.0001
Run Code Online (Sandbox Code Playgroud)

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

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())
Run Code Online (Sandbox Code Playgroud)

  • 问题询问如何“不诉诸类似”的方法 (2认同)
  • py.test现在有一个功能,可以做到这一点.我已经添加了一个讨论它的答案. (2认同)
  • @NeilG 为什么要删除这个?如果有什么明显的问题,请解释它是什么。 (2认同)

jif*_*lub 30

如果您可以访问NumPy,它具有很好的浮点比较功能,已经与成对比较numpy.testing.

然后你可以这样做:

numpy.testing.assert_allclose(i_return_tuple_of_two_floats(), (1.32, 2.4))
Run Code Online (Sandbox Code Playgroud)


Joh*_*ooy 11

就像是

assert round(x-y, 5) == 0
Run Code Online (Sandbox Code Playgroud)

这就是unittest所做的

第二部分

assert all(round(x-y, 5) == 0 for x,y in zip((1.32, 2.4), i_return_tuple_of_two_floats()))
Run Code Online (Sandbox Code Playgroud)

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

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())
Run Code Online (Sandbox Code Playgroud)


Kob*_*ohn 11

这些答案已经存在了很长时间,但我认为最简单也是最易读的方法是使用unittest,因为它没有将它用于测试结构的许多好的断言.

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

(基于这个答案)

import unittest

assertions = unittest.TestCase('__init__')
Run Code Online (Sandbox Code Playgroud)

做一些断言

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

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

只需使用*来解压缩返回值,而无需引入新名称.

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
Run Code Online (Sandbox Code Playgroud)


val*_*ame 11

如果您想要的东西不仅适用于浮点数,而且适用于小数,您可以使用 python 的math.isclose

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

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


vol*_*myr 5

我会使用nose.tools。它与 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 
Run Code Online (Sandbox Code Playgroud)

  • 除了 pytest 有一个选项之外,我不认为为此添加额外的依赖项(在本例中是整个测试框架)是一个好的选择。 (2认同)