Załóżmy, że mamy coś takiego:
import py, pytest
ERROR1 = ' --- Error : value < 5! ---'
ERROR2 = ' --- Error : value > 10! ---'
class MyError(Exception):
def __init__(self, m):
self.m = m
def __str__(self):
return self.m
def foo(i):
if i < 5:
raise MyError(ERROR1)
elif i > 10:
raise MyError(ERROR2)
return i
# ---------------------- TESTS -------------------------
def test_foo1():
with pytest.raises(MyError) as e:
foo(3)
assert ERROR1 in str(e)
def test_foo2():
with pytest.raises(MyError) as e:
foo(11)
assert ERROR2 in str(e)
def test_foo3():
....
foo(7)
....
P: Jak mogę sprawić, by test_foo3 () sprawdzał, czy nie pojawia się MyError? To oczywiste, że mógłbym po prostu przetestować:
def test_foo3():
assert foo(7) == 7
ale chcę to przetestować poprzez pytest.raises (). Czy jest to możliwe? Na przykład: w przypadku funkcja „foo” w ogóle nie ma wartości zwracanej,
def foo(i):
if i < 5:
raise MyError(ERROR1)
elif i > 10:
raise MyError(ERROR2)
może mieć sens testowanie w ten sposób, imho.
foo(7)
jest w porządku. Otrzymasz odpowiednią wiadomość i łatwiej będzie debugować wszystkie dane wyjściowe pytest. Sugestia, którą wymusiłeś z @Faruk ('Unexpected error...'
) nie mówi nic o błędzie i utkniesz. Jedyne, co możesz zrobić, aby to poprawić, to wyrazić swój zamiartest_foo3_works_on_integers_within_range()
.Odpowiedzi:
Test zakończy się niepowodzeniem, jeśli wystąpi jakikolwiek nieoczekiwany wyjątek. Możesz po prostu wywołać foo (7) i sprawdzisz, czy nie pojawia się MyError. Tak więc wystarczy:
def test_foo3(): foo(7)
Jeśli chcesz być wyraźny i napisać w tym celu oświadczenie asertujące, możesz zrobić:
def test_foo3(): try: foo(7) except MyError: pytest.fail("Unexpected MyError ..")
źródło
Opierając się na tym, o czym wspomniał Oisin.
Możesz stworzyć prostą
not_raises
funkcję działającą podobnie do pytestraises
:from contextlib import contextmanager @contextmanager def not_raises(exception): try: yield except exception: raise pytest.fail("DID RAISE {0}".format(exception))
To jest w porządku, jeśli chcesz się trzymać
raises
mieć odpowiednik, a tym samym wyniki testów są bardziej czytelne. W istocie jednak nie potrzebujesz niczego poza uruchomieniem bloku kodu, który chcesz przetestować we własnym wierszu - pytest i tak zakończy się niepowodzeniem, gdy tylko ten blok zgłosi błąd.źródło
@pytest.mark.parametrize
.Byłem ciekawy, czy not_raises zadziała. Szybki test to (test_notraises.py):
from contextlib import contextmanager @contextmanager def not_raises(ExpectedException): try: yield except ExpectedException, err: raise AssertionError( "Did raise exception {0} when it should not!".format( repr(ExpectedException) ) ) except Exception, err: raise AssertionError( "An unexpected exception {0} raised.".format(repr(err)) ) def good_func(): print "hello" def bad_func(): raise ValueError("BOOM!") def ugly_func(): raise IndexError("UNEXPECTED BOOM!") def test_ok(): with not_raises(ValueError): good_func() def test_bad(): with not_raises(ValueError): bad_func() def test_ugly(): with not_raises(ValueError): ugly_func()
Wydaje się, że to działa. Jednak nie jestem pewien, czy naprawdę dobrze się czyta w teście.
źródło