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 2016

その機能の説明については、この回答を参照してください
Tom Hale

回答:


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])
Mr Kriss

4
@Mr Krissそしてディクトのためにさえ:assert {'a': 0.1+0.2} == pytest.approx({'a': 0.3})
アントニーハッチキンズ

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]])(以下の回答を参照)がこのケースで機能したことが判明した場合。
カートピーク2017

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
質問は、「このようなものに頼ることなく」どのようにそれを行うのかを尋ねます
内部石2016

私は「このようなもの」をのような反復的で厄介な表現として解釈しますがx - d <= y <= x+d、それもOPが意味していたようです。「ほぼ」のしきい値を明示的に指定したくない場合は、@ jiffyclubの回答を参照してください。
yurib

2
py.testに、これを行う機能が追加されました。それについて議論する答えを追加しました。
dbn

2
@NeilGなぜこれを削除する必要があるのですか?明らかに何か問題がある場合は、それが何かを説明してください。
user2699 2018年

1
@ user2699問題は、pytestでこれを行う方法です。pytestでそれを行う正しい方法は、を使用することpytest.approxです。独自の近似関数を書くことは悪い考えです。(この回答の1つは、含まれているものほど良くありません。)
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.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

floatだけでなく、たとえばDecimalsでも機能するものが必要な場合は、pythonを使用できます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


ここでは、相対的な許容誤差(またはパーセンテージの差)は、scienfificなどの一部のユースケースで使用すると便利です。
かりおき

3

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 

2
pytestにはこのためのオプションがあるほか、これだけのために余分な必要性(この場合はテスト全体のフレームワーク)を追加する良いオプションは考えていません。
MarcTudurí2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.