pytest: khẳng định gần như bằng nhau


145

Cách thực hiện assert almost equalvới py.test cho phao mà không cần dùng đến một cái gì đó như:

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

Cụ thể hơn sẽ hữu ích khi biết một giải pháp gọn gàng để nhanh chóng so sánh các cặp float mà không cần giải nén chúng:

assert (1.32, 2.4) == i_return_tuple_of_two_floats()

3
py.test hiện có một tính năng thực hiện điều này.
dbn

Xem câu trả lời này để biết mô tả về tính năng đó
Tom Hale

Câu trả lời:


232

Tôi nhận thấy rằng câu hỏi này đặc biệt hỏi về py.test. py.test 3.0 bao gồm một approx()hàm (tốt, thực sự là lớp) rất hữu ích cho mục đích này.

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

Tài liệu có tại đây: https://docs.pytest.org/en/latest/reference.html#pytest-approx


12
Đẹp! Cũng tìm thấy nó hoạt động cho chuỗi số quá, ví dụassert [0.1 + 0.2, 0.2 + 0.4] == pytest.approx([0.3, 0.6])
Mr Kriss

4
@Mr Kriss Và thậm chí cho các câu chuyện:assert {'a': 0.1+0.2} == pytest.approx({'a': 0.3})
Antony Hatchkins

4
Điều này không làm việc cho danh sách các danh sách: ví dụ, assert [[0.1 + 0.2], [0.2 + 0.4]] == pytest.approx([[0.3], [0.6]])dẫn đến a TypeError. Nếu thấy rằng Numpy np.testing.assert_allclose([[0.1 + 0.2], [0.2 + 0.4]], [[0.3], [0.6]])(xem câu trả lời dưới đây) đã làm việc cho trường hợp này.
Kurt Peek

43

Bạn sẽ phải xác định những gì "gần như" cho bạn:

assert abs(x-y) < 0.0001

để áp dụng cho các bộ dữ liệu (hoặc bất kỳ chuỗi nào):

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
Câu hỏi đặt ra yêu cầu như thế nào để làm điều đó "mà không cần đến một cái gì đó giống như" này
endolith

Tôi diễn giải "một cái gì đó như thế này" là một biểu hiện lặp đi lặp lại và vụng về như thế x - d <= y <= x+d, có vẻ như đó cũng là ý nghĩa của OP. Nếu bạn không muốn chỉ định rõ ràng ngưỡng cho 'gần như', hãy xem câu trả lời của @ jiffyclub.
yurib

2
py.test hiện có một tính năng thực hiện điều này. Tôi đã thêm một câu trả lời thảo luận về nó.
dbn

2
@NeilG Tại sao điều này trên trái đất nên được xóa? Nếu có gì đó rõ ràng sai với nó, xin vui lòng giải thích nó là gì.
dùng2699

1
@ user2699 Câu hỏi là làm thế nào để làm điều này trong pytest. Cách chính xác để làm điều đó trong pytest là sử dụng pytest.approx. Viết chức năng gần đúng của riêng bạn là một ý tưởng tồi. (Câu trả lời trong câu trả lời này thậm chí không tốt bằng câu trả lời.)
Neil G

31

Nếu bạn có quyền truy cập vào NumPy, nó có các chức năng tuyệt vời để so sánh điểm nổi đã thực hiện so sánh theo cặp numpy.testing.

Sau đó, bạn có thể làm một cái gì đó như:

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

11

Cái gì đó như

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

Đó là những gì unittest làm

Đối với phần thứ hai

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

Có lẽ tốt hơn để bọc nó trong một chức năng

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

Những câu trả lời này đã có từ lâu, nhưng tôi nghĩ cách dễ nhất và cũng dễ đọc nhất là sử dụng ít nhất cho nhiều xác nhận tốt đẹp mà không sử dụng nó cho cấu trúc thử nghiệm.

Nhận các xác nhận, bỏ qua phần còn lại của unittest.TestCase

(dựa trên câu trả lời này )

import unittest

assertions = unittest.TestCase('__init__')

Thực hiện một số khẳng định

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

Thực hiện kiểm tra tự động giải nén câu hỏi ban đầu

Chỉ cần sử dụng * để giải nén giá trị trả về của bạn mà không cần phải giới thiệu tên mới.

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

Nếu bạn muốn một cái gì đó hoạt động không chỉ với phao mà ví dụ như Decimals, bạn có thể sử dụng python's math.isclose:

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

Tài liệu - https://docs.python.org/3/l Library / math.html # math.isclose


Ở đây dung sai tương đối (hoặc chênh lệch tỷ lệ phần trăm) thuận tiện để sử dụng trong một số trường hợp sử dụng, ví dụ như scienfific.
Karioki

3

Tôi sẽ sử dụng mũi.tools. Nó chơi tốt với người chạy py.test và có các xác nhận hữu ích khác không kém - assert_dict_equal (), assert_list_equal (), v.v.

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

2
Bên cạnh đó, pytest có một tùy chọn cho việc này, tôi không xem xét một lựa chọn tốt bổ sung thêm một phụ thuộc (trong trường hợp này, toàn bộ khung thử nghiệm) chỉ dành cho việc này.
Marc Tudurí
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.