pytest: утверждать почти равным - PullRequest
97 голосов
/ 19 декабря 2011

Как сделать assert almost equal с py.test для поплавков, не прибегая к чему-то вроде:

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

Точнее, будет полезно найти точное решение для быстрого сравнения пар поплавков без их распаковки:

assert (1.32, 2.4) == i_return_tuple_of_two_floats()

Ответы [ 7 ]

169 голосов
/ 21 сентября 2016

Я заметил, что этот вопрос специально задавался о 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

40 голосов
/ 19 декабря 2011

Вам нужно будет указать, что для вас «почти»:

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())
29 голосов
/ 19 апреля 2013

Если у вас есть доступ к NumPy, у него есть отличные функции для сравнения с плавающей запятой, которые уже выполняют попарное сравнение с numpy.testing.

Тогда вы можете сделать что-то вроде:

numpy.testing.assert_allclose(i_return_tuple_of_two_floats(), (1.32, 2.4))
11 голосов
/ 19 декабря 2011

Что-то вроде

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())
9 голосов
/ 08 июня 2016

Эти ответы существуют уже давно, но я думаю, что самый простой и читаемый способ - использовать unittest для его множества хороших утверждений без использования его для структуры тестирования.

Получить утверждения, игнорировать остаток от 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
2 голосов
/ 07 февраля 2019

Если вам нужно что-то, что работает не только с числами с плавающей запятой, но, например, с десятичными знаками, вы можете использовать math.isclose:

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

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

2 голосов
/ 16 июня 2016

Я бы использовал nose.tools. Он хорошо работает с py.test runner и имеет другие не менее полезные утверждения - assert_dict_equal (), assert_list_equal () и т. Д.

from nose.tools import assert_almost_equals
assert_almost_equals(x, y, places=7) #default is 7 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...