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

ดูคำตอบสำหรับคำอธิบายของคุณลักษณะนั้น
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 และแม้แต่ dicts:assert {'a': 0.1+0.2} == pytest.approx({'a': 0.3})
Antony Hatchkins

4
สิ่งนี้ใช้ไม่ได้กับรายการของรายการ: ตัวอย่างเช่นassert [[0.1 + 0.2], [0.2 + 0.4]] == pytest.approx([[0.3], [0.6]])นำไปสู่ ​​aTypeErrorนำไปสู่การหากพบว่า 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 ทำไมต้องลบสิ่งนี้บนโลก? หากมีบางอย่างผิดปกติกับมันโปรดอธิบายว่ามันคืออะไร
2699

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

นั่นคือสิ่งที่UnitTestไม่

สำหรับส่วนที่สอง

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

คำตอบเหล่านี้มีมานานแล้ว แต่ฉันคิดว่าวิธีที่ง่ายที่สุดและอ่านง่ายที่สุดคือการใช้สิ่งที่ไม่สำคัญเพราะมันเป็นคำยืนยันที่ดีมากโดยไม่ต้องใช้มันสำหรับโครงสร้างการทดสอบ

รับการยืนยันละเว้นส่วนที่เหลือของการทดสอบ 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

หากคุณต้องการบางสิ่งที่ใช้งานไม่ได้กับโฟลทเท่านั้น แต่ตัวอย่างเช่นทศนิยมคุณสามารถใช้ไพ ธ อน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
Karioki

3

ฉันจะใช้เครื่องมือเสริมจมูก มันเล่นได้ดีกับนักวิ่ง py.test และมี asserts ที่มีประโยชน์อื่น ๆ อย่างเท่าเทียมกัน - 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 มีตัวเลือกสำหรับสิ่งนี้ฉันไม่พิจารณาตัวเลือกที่ดีเพิ่มการพึ่งพาพิเศษ (ในกรณีนี้เป็นกรอบการทดสอบทั้งหมด) เฉพาะสำหรับสิ่งนี้
Marc Tudurí
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.