2011-12-19 3 views
44

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

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

Более конкретно это будет полезно знать, изящное решение для быстрого сравнения пары поплавка, без распаковка их:

assert (1.32, 2.4) == i_return_tuple_of_two_floats() 
+3

py.test теперь есть функция, которая делает это. – dbn

+0

См. [Этот ответ] (https://stackoverflow.com/a/39623614/5353461) для описания этой функции –

ответ

75

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

Документация находится здесь: http://doc.pytest.org/en/latest/builtin.html#pytest.approx

+5

Ницца! Также найдено, что он работает для последовательностей чисел, например. 'assert [0.1 + 0.2, 0.2 + 0.4] == pytest.approx ([0.3, 0.6])' –

+2

@Mr Kriss И даже для dicts: 'assert {'a': 0.1 + 0.2} == pytest.approx ({'a': 0.3}) ' –

+2

Это должен быть принятый ответ. – jstol

35

Вы должны указать, что это "почти" для вас:

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()) 
+1

Вопрос задает вопрос, как это сделать «не прибегая к чему-то вроде этого» – endolith

+0

Я интерпретирую «что-то вроде этого «как повторяющееся и неловкое выражение типа« x-d <= y <= x + d', похоже, это то, что означает OP. Если вы не хотите явно указывать порог «почти», см. Ответ @ jiffyclub. – yurib

+2

Теперь у py.test есть функция, которая делает это. Я добавил ответ, обсуждая его. – dbn

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()) 
22

Если у вас есть доступ к NumPy, у него есть отличные функции для сравнения с плавающей запятой, которые уже делают попарное сравнение: http://docs.scipy.org/doc/numpy-dev/reference/routines.testing.html.

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

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

Эти ответы были вокруг в течение долгого времени, но я думаю, что самый простой и также самым читаемым способом является использование UnitTest для его many nice assertions без его использования для структура тестирования.

Получить утверждения, игнорировать остальную часть unittest.TestCase

(на основе this answer)

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

Я бы использовал нос.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 есть опция для этого, я не считаю, что хороший вариант добавляет дополнительную возможность (в данном случае целую тестовую фреймворк) только для этого. –

Смежные вопросы