Pytest का उपयोग कैसे करें यह जांचने के लिए कि त्रुटि नहीं उठाई गई है


86

चलिए मान लेते हैं कि हमारे पास ऐसा है:

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

प्रश्न: मैं परीक्षण करने के लिए test_foo3 () कैसे बना सकता हूं कि कोई MyError नहीं बढ़ा है? यह स्पष्ट है, कि मैं अभी परीक्षण कर सकता हूं:

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

लेकिन मैं pytest.raises () के माध्यम से परीक्षण करना चाहता हूं। क्या कोई संभव है? उदाहरण के लिए: एक मामले में, उस फ़ंक्शन "फू" का कोई रिटर्न-वैल्यू नहीं है,

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

यह इस तरह से परीक्षण करने के लिए समझ में आता है, इम्हो।


ऐसा लगता है कि किसी समस्या की खोज हो रही है, कोड परीक्षण foo(7)ठीक है। आपको सही संदेश मिलेगा और सभी पाइस्टेस्ट आउटपुट के साथ डिबग करना आसान होगा। @Faruk ( 'Unexpected error...') से आपने जो सुझाव मांगा था वह त्रुटि के बारे में कुछ नहीं कहता है और आप अटक जाएंगे। केवल एक चीज जो आप इसे बेहतर बनाने के लिए कर सकते हैं वह है जैसे आपका इरादा test_foo3_works_on_integers_within_range()
ढिल्ले

जवाबों:


129

यदि यह किसी प्रकार का अप्रत्याशित अपवाद उठाता है तो एक परीक्षा विफल हो जाएगी। आप केवल फू (7) को आमंत्रित कर सकते हैं और आपने परीक्षण किया होगा कि कोई MyError नहीं बढ़ा है। तो, निम्नलिखित पर्याप्त होगा:

def test_foo3():
    foo(7)

यदि आप स्पष्ट होना चाहते हैं और इसके लिए एक मुखर वक्तव्य लिखना चाहते हैं, तो आप यह कर सकते हैं:

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

3
धन्यवाद, यह काम करता है, लेकिन यह एक स्वच्छ समाधान की तुलना में अधिक हैक लगता है। उदाहरण के लिए, फू (4) के लिए परीक्षण विफल हो जाएगा, लेकिन दावे की त्रुटि के कारण नहीं।
पैराक्लेट

फू (4) के लिए परीक्षण विफल हो जाएगा क्योंकि यह एक अपवाद फेंक देगा जिसकी उम्मीद नहीं थी। एक अन्य तरीका यह होगा कि आप इसे एक ट्राई कैच ब्लॉक में लपेटें और एक विशिष्ट संदेश के साथ असफल हो जाएं। मैं अपना जवाब अपडेट करूंगा।
फारुक साहिन

1
यदि आपके पास इस तरह के बहुत सारे मामले हैं, तो इसे एक साधारण फ़ंक्शन में लिखना उपयोगी हो सकता है: `` `not_raises (error_class, func, * args, ** kwargs): ...` `या आप लिख सकते हैं a pytest की तरह दृष्टिकोण के साथ करता है। यदि आप मुझे सुझाव देते हैं कि आप सभी को लाभ पहुंचाने के लिए इसके साथ एक पीआर लिखें। :) (रिपॉजिटरी बिटबकेट में है )।
ब्रूनो ओलिवेरा

6
@paraklet - पाइस्टेस्ट की मुख्य टैगलाइन "नो-बॉयलरप्लेट टेस्टिंग" है । पाइरेस्ट की भावना में यह बहुत ज्यादा है कि आप फारुक के पहले उदाहरण की तरह परीक्षण लिखने में सक्षम हो सकते हैं जबकि पाइस्टेस्ट आपके लिए विवरण संभालता है। मेरे लिए, पहला उदाहरण "स्वच्छ समाधान" है और दूसरा अनावश्यक रूप से क्रिया लगता है।
निक चामास

22

ओइसिन ने जो उल्लेख किया है उसके शीर्ष पर निर्माण ।।

आप एक साधारण not_raisesकार्य कर सकते हैं जो पाइएस्ट के समान कार्य करता है raises:

from contextlib import contextmanager

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

यह ठीक है अगर आप raisesएक समकक्ष होने के लिए छड़ी चाहते हैं और इस प्रकार आपके परीक्षण अधिक पठनीय हैं। संक्षेप में, आपको वास्तव में कोड के ब्लॉक को चलाने की तुलना में कुछ भी करने की आवश्यकता नहीं है जिसे आप अपनी लाइन पर परीक्षण करना चाहते हैं - जैसे ही वह ब्लॉक त्रुटि उठाता है वैसे ही पूरी तरह से विफल हो जाएगा।


1
काश यह py.test में बनाया गया था; यह कुछ मामलों में परीक्षणों को अधिक पठनीय बना देगा। विशेष रूप से के साथ संयोजन के रूप में @pytest.mark.parametrize
अरेल

मैं इस दृष्टिकोण में कोड पठनीयता की भावना की बहुत सराहना करता हूं!
ग्राज़िंग साइंटिस्ट

7

मैं यह देखने के लिए उत्सुक था कि क्या not_raises काम करेगा। इसका एक त्वरित परीक्षण है (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()

यह काम करने लगता है। हालांकि मुझे यकीन नहीं है कि यह वास्तव में परीक्षण में अच्छा है।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.