2011-12-19 14 views
44

Cómo hacer assert almost equal con py.test de los flotadores sin tener que recurrir a algo como:PYtest: valer casi igual

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

Más específicamente, será útil conocer una solución ordenada para comparar rápidamente los pares de flotador, sin desempaquetarlos:

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

py.test ahora tiene una característica que lo hace. – dbn

+0

Consulte [esta respuesta] (https://stackoverflow.com/a/39623614/5353461) para obtener una descripción de esa función –

Respuesta

75

me di cuenta de que esta pregunta le preguntó específicamente sobre py.test. py.test 3.0 incluye una función approx() (bueno, realmente clase) que es muy útil para este propósito.

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 

La documentación está aquí: http://doc.pytest.org/en/latest/builtin.html#pytest.approx

+5

¡Agradable! También se encontró que funciona para secuencias de números también, p. 'assert [0.1 + 0.2, 0.2 + 0.4] == pytest.approx ([0.3, 0.6])' –

+2

@Mr Kriss E incluso para dicts: 'assert {'a': 0.1 + 0.2} == pytest.approx ({'a': 0.3}) ' –

+2

Esta debería ser la respuesta aceptada. – jstol

35

tendrá que especificar lo que es "casi" para usted:

assert abs(x-y) < 0.0001 

aplicar a tuplas (o cualquier secuencia):

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

La pregunta es cómo hacerlo "sin recurrir a algo como" esto – endolith

+0

interpreto "algo como esto "como una expresión repetitiva e incómoda como' x - d <= y <= x + d ', parece que eso es lo que también significa OP. Si no desea especificar explícitamente el umbral para "casi", consulte la respuesta de @ jiffyclub. – yurib

+2

py.test ahora tiene una función que hace esto. He agregado una respuesta para discutirlo. – dbn

11

Algo así como

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

Eso es lo que unittest hace

Para la segunda parte

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

Probablemente es mejor envolver eso en una función

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

Estas respuestas han existido por mucho tiempo, pero creo que el más fácil y también forma más legible es utilizar unittest por su many nice assertions sin usarlo para el estructura de prueba.

Obtener afirmaciones, ignorar resto de unittest.TestCase

(basado en this answer)

import unittest 

assertions = unittest.TestCase('__init__') 

hacen que algunas afirmaciones

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

Implementar la prueba de auto-desembalaje preguntas originales

Solo use * para desempaquetar su valor de retorno sin needi ng para introducir nuevos nombres.

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

Utilizaría nose.tools. Se juega bien con el corredor py.test y tienen otra igualmente útil afirma - assert_dict_equal(), assert_list_equal(), etc.

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

Además de que Pytest tiene una opción para esto, no considero que una buena opción agregue una dependencia adicional (en este caso, una estructura de prueba completa) solo para esto. –