2011-12-19 20 views
44

Jak zrobić assert almost equal z py.test dla pływaków bez uciekania się do czegoś takiego:pytest: dochodzić prawie równa

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

Dokładniej będzie to przydatne wiedzieć schludny rozwiązanie dla szybkiego porównania par pływaka, bez rozpakowanie je:

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

py.test ma teraz funkcję, która to robi. – dbn

+0

Zobacz [tę odpowiedź] (https://stackoverflow.com/a/39623614/5353461), aby uzyskać opis tej funkcji. –

Odpowiedz

75

Zauważyłem, że kwestia ta specjalnie poprosił o py.test. py.test 3.0 zawiera funkcję approx() (cóż, naprawdę klasa), która jest bardzo przydatna do tego celu.

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 

Dokumentacja jest tutaj: http://doc.pytest.org/en/latest/builtin.html#pytest.approx

+5

Nice! Okazało się, że działa również dla sekwencji liczb, np. 'assert [0.1 + 0.2, 0.2 + 0.4] == pytest.approx ([0.3, 0.6])' –

+2

@Mr Kriss A nawet dla dyktów: 'assert {'a': 0.1 + 0.2} == pytest.approx ({'a': 0.3}) ' –

+2

To powinna być zaakceptowana odpowiedź. – jstol

35

trzeba będzie określić, co jest "prawie" dla Ciebie:

assert abs(x-y) < 0.0001 

stosuje się do krotek (lub dowolnej kolejności):

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

Pytanie pyta, jak to zrobić "bez uciekania się do czegoś takiego" to – endolith

+0

interpretuję "coś takiego" "jak powtarzające się i niewygodne wyrażenie, takie jak' x - d <= y <= x + d', wydaje się, że właśnie to oznacza OP. Jeśli nie chcesz jednoznacznie określać progu "prawie", zobacz odpowiedź @ jiffyclub. – yurib

+2

py.test ma teraz funkcję, która to robi. Dodałem odpowiedź na ten temat. – dbn

11

Coś podobnego

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

To właśnie unittest robi

Dla drugiej części

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

chyba lepiej zawiń w funkcję

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

Odpowiedzi te zostały od dłuższego czasu, ale myślę, że to najprostszy i także najbardziej czytelny sposób jest wykorzystanie unittest za to many nice assertions bez używania go dla struktura testowa.

Get twierdzeń, zignorować resztę unittest.TestCase

(na podstawie this answer)

import unittest 

assertions = unittest.TestCase('__init__') 

Dodać kilka twierdzeń

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

Wdrożenie automatycznego rozpakowywania badanie oryginalnych pytań

Wystarczy użyć *, aby rozpakować swoją wartość zwrotu bez potrzeby ng, aby wprowadzić nowe nazwy.

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

Używałbym nos.tools. Odgrywa również z py.test biegacza i mają innych równie przydatnych twierdzi - assert_dict_equal(), assert_list_equal(), itd

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

Oprócz pytest ma opcję dla tego nie uważam za dobrą opcję dodać dodatkową depencję (w tym przypadku cały framwork badania) tylko do tego. –