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.