pytest: nyatakan hampir sama


145

Bagaimana hubungannya assert almost equaldengan py.test untuk mengapung tanpa menggunakan sesuatu seperti:

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

Lebih khusus akan berguna untuk mengetahui solusi yang rapi untuk dengan cepat membandingkan pasangan float, tanpa membongkar mereka:

assert (1.32, 2.4) == i_return_tuple_of_two_floats()

3
py.test sekarang memiliki fitur yang melakukan ini.
dbn

Lihat jawaban ini untuk deskripsi fitur itu
Tom Hale

Jawaban:


232

Saya perhatikan bahwa pertanyaan ini secara khusus bertanya tentang py.test. py.test 3.0 termasuk approx()fungsi (well, really class) yang sangat berguna untuk tujuan ini.

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

Dokumentasi ada di sini: https://docs.pytest.org/en/latest/reference.html#pytest-approx


12
Bagus! Juga menemukan itu berfungsi untuk urutan angka juga misalnyaassert [0.1 + 0.2, 0.2 + 0.4] == pytest.approx([0.3, 0.6])
Mr Kriss

4
@Mr Kriss Dan bahkan untuk dikte:assert {'a': 0.1+0.2} == pytest.approx({'a': 0.3})
Antony Hatchkins

4
Ini tidak berfungsi untuk daftar daftar: misalnya, assert [[0.1 + 0.2], [0.2 + 0.4]] == pytest.approx([[0.3], [0.6]])mengarah ke a TypeError. Jika ternyata Numpy np.testing.assert_allclose([[0.1 + 0.2], [0.2 + 0.4]], [[0.3], [0.6]])(lihat jawaban di bawah) berhasil untuk kasus ini.
Kurt Peek

43

Anda harus menentukan apa yang "hampir" untuk Anda:

assert abs(x-y) < 0.0001

untuk diterapkan pada tupel (atau urutan apa pun):

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
Pertanyaannya menanyakan bagaimana cara melakukannya "tanpa menggunakan sesuatu seperti" ini
endolith

Saya menafsirkan "sesuatu seperti ini" sebagai ekspresi berulang dan canggung seperti x - d <= y <= x+d, sepertinya itulah yang dimaksud OP juga. Jika Anda tidak ingin menentukan ambang secara eksplisit untuk 'hampir', lihat jawaban @ jiffyclub.
yurib

2
py.test sekarang memiliki fitur yang melakukan ini. Saya telah menambahkan jawaban untuk membahasnya.
dbn

2
@ NeilG Kenapa ini harus dihapus? Jika ada sesuatu yang salah dengan itu, tolong jelaskan apa itu.
user2699

1
@ user2699 Pertanyaannya adalah bagaimana melakukan ini di pytest. Cara yang benar untuk melakukannya di pytest adalah menggunakan pytest.approx. Menulis fungsi perkiraan Anda sendiri adalah ide yang buruk. (Jawaban dalam jawaban ini bahkan tidak sebaik jawaban yang disertakan.)
Neil G

31

Jika Anda memiliki akses ke NumPy, ia memiliki fungsi hebat untuk perbandingan titik mengambang yang sudah melakukan perbandingan berpasangan numpy.testing.

Maka Anda dapat melakukan sesuatu seperti:

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

11

Sesuatu seperti

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

Itulah yang unittest tidak

Untuk bagian kedua

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

Mungkin lebih baik untuk membungkusnya dalam suatu fungsi

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

Jawaban ini sudah ada sejak lama, tetapi saya pikir cara termudah dan juga paling mudah dibaca adalah menggunakan unittest untuk banyak asersi bagus tanpa menggunakannya untuk struktur pengujian.

Dapatkan pernyataan, abaikan sisa unittest.TestCase

(berdasarkan jawaban ini )

import unittest

assertions = unittest.TestCase('__init__')

Buat beberapa pernyataan

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

Laksanakan tes pembongkaran otomatis pertanyaan asli

Cukup gunakan * untuk membongkar nilai pengembalian Anda tanpa harus memasukkan nama baru.

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

Jika Anda menginginkan sesuatu yang berfungsi tidak hanya dengan float tetapi misalnya Desimal Anda dapat menggunakan python math.isclose:

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

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


Di sini toleransi relatif (atau perbedaan persentase) nyaman digunakan dalam beberapa kasus penggunaan, misalnya ilmiah.
Karioki

3

Saya akan menggunakan nose.tools. Ini dimainkan dengan baik oleh pelari py.test dan memiliki pernyataan yang sama bermanfaat lainnya - assert_dict_equal (), assert_list_equal (), dll.

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

2
Selain pytest memiliki opsi untuk ini, saya tidak menganggap opsi yang baik menambahkan kemandirian ekstra (dalam hal ini, seluruh kerangka pengujian) hanya untuk ini.
Marc Tudurí
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.