Pytest, Hatanın yükseltilmediğini kontrol etmek için nasıl kullanılır?


86

Diyelim ki böyle bir şeyimiz var:

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)
         ....

S: Test_foo3 () 'ün hiçbir MyError oluşturulmadığını test etmesini nasıl sağlayabilirim? Belli ki test edebileceğim:

def test_foo3():
    assert foo(7) == 7

ancak bunu pytest.raises () aracılığıyla test etmek istiyorum. Bir şekilde mümkün mü? Örneğin: bir durumda, bu "foo" işlevinin hiçbir dönüş değeri yoktur,

def foo(i):
    if i < 5:
        raise MyError(ERROR1)
    elif i > 10:
        raise MyError(ERROR2)

Bu şekilde test etmek mantıklı olabilir, imho.


Bir problem arıyor gibi görünüyor, kod testi foo(7)iyi. Doğru mesajı alırsınız ve tüm pytest çıktılarıyla hata ayıklamak daha kolay olacaktır. @ Faruk ( 'Unexpected error...') ' dan zorladığınız öneri hata hakkında hiçbir şey söylemiyor ve takılıp kalacaksınız. Bunu daha iyi hale getirmek için yapabileceğiniz tek şey, niyetinizi belirtmektir test_foo3_works_on_integers_within_range().
dhill

Yanıtlar:


129

Herhangi bir beklenmedik İstisna ortaya çıkarırsa bir test başarısız olacaktır. Sadece foo (7) 'yi çağırabilirsiniz ve MyError'ın yükselmediğini test etmiş olursunuz. Yani, aşağıdakiler yeterli olacaktır:

def test_foo3():
    foo(7)

Açık olmak ve bunun için bir assert ifadesi yazmak istiyorsanız, şunları yapabilirsiniz:

def test_foo3():
    try:
        foo(7)
    except MyError:
        pytest.fail("Unexpected MyError ..")

3
Teşekkürler, işe yarıyor, ancak temiz bir çözümden çok bir hack gibi görünüyor. Örneğin, foo (4) testi başarısız olur, ancak onaylama hatası nedeniyle olmaz.
paraklet

foo (4) için test, beklenmeyen bir istisna atacağından başarısız olacaktır. Diğer bir yol, onu bir try catch bloğuna sarmak ve belirli bir mesajla başarısız olmaktır. Cevabımı güncelleyeceğim.
Faruk Şahin

1
Bunun gibi çok sayıda durumunuz varsa, bunu basit bir işlevle yazmak yararlı olabilir: `` def not_raises (error_class, func, * args, ** kwargs): ... `` Veya bir pytest'in yaptığı gibi benzer bir yaklaşım. Bunu yaparsanız, herkese fayda sağlamak için bununla bir PR yazmanızı öneririm. :) (Depo bitbucket içindedir ).
Bruno Oliveira

6
@paraklet - pytest'in ana sloganı " şablonsuz test" dir . Pytest ayrıntıları sizin için ele alırken, faruk'un ilk örneğindeki gibi testler yazmanıza olanak sağlamak pytest ruhuna çok yakışıyor. Bana göre ilk örnek "temiz çözüm" ve ikincisi gereksiz yere ayrıntılı görünüyor.
Nick Chammas

22

Oisin'in bahsettiği şeylerin üzerine inşa ediliyor ..

not_raisesPytest'lere benzer şekilde davranan basit bir işlev yapabilirsiniz raises:

from contextlib import contextmanager

@contextmanager
def not_raises(exception):
  try:
    yield
  except exception:
    raise pytest.fail("DID RAISE {0}".format(exception))

raisesBir benzerine sahip olmak ve böylece testlerinizin daha okunaklı olmasını istiyorsanız, bu sorun değil. Temelde, test etmek istediğiniz kod bloğunu kendi satırında çalıştırmaktan başka bir şeye ihtiyacınız yok - bu blok bir hata çıkardığında pytest yine de başarısız olacaktır.


1
Bunun py.test içine yerleştirilmesini dilerdim; bazı durumlarda testleri çok daha okunaklı hale getirirdi. Özellikle ile bağlantılı olarak @pytest.mark.parametrize.
Arel

Bu yaklaşımdaki kod okunabilirliği duygusunu çok takdir ediyorum!
GrazingScientist

7

Bir not_reises işe yarayıp yaramayacağını merak ediyordum. Bunun hızlı bir testi (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()

İşe yarıyor gibi görünüyor. Ancak testte gerçekten iyi okuduğundan emin değilim.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.