कैसे ठीक से दावा है कि एक अपवाद pytest में उठाया जाता है?


293

कोड:

# coding=utf-8
import pytest


def whatever():
    return 9/0

def test_whatever():
    try:
        whatever()
    except ZeroDivisionError as exc:
        pytest.fail(exc, pytrace=True)

आउटपुट:

================================ test session starts =================================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
plugins: django, cov
collected 1 items 

pytest_test.py F

====================================== FAILURES ======================================
___________________________________ test_whatever ____________________________________

    def test_whatever():
        try:
            whatever()
        except ZeroDivisionError as exc:
>           pytest.fail(exc, pytrace=True)
E           Failed: integer division or modulo by zero

pytest_test.py:12: Failed
============================== 1 failed in 1.16 seconds ==============================

कैसे pytest प्रिंट ट्रेसबैक बनाने के लिए, इसलिए मैं देखूंगा कि whateverफ़ंक्शन में एक अपवाद कहां उठाया गया था?


मुझे पूरा ट्रेसबैक मिला, उबंटू 14.04, पायथन 2.7.6
thefourtheye

@thefourtheye कृपया आउटपुट के साथ जिस्ट बनाएं। मैंने पायथन 2.7.4 और उबुनथु 14.04 के साथ कोशिश की - जैसा कि मैंने मुख्य पोस्ट में वर्णित किया है।
गिल बेट्स

1
@GillBates क्या आप सही उत्तर दे सकते हैं ??
गोंजालो गार्सिया

जवाबों:


332

pytest.raises(Exception) आपको क्या चाहिए

कोड

import pytest

def test_passes():
    with pytest.raises(Exception) as e_info:
        x = 1 / 0

def test_passes_without_info():
    with pytest.raises(Exception):
        x = 1 / 0

def test_fails():
    with pytest.raises(Exception) as e_info:
        x = 1 / 1

def test_fails_without_info():
    with pytest.raises(Exception):
        x = 1 / 1

# Don't do this. Assertions are caught as exceptions.
def test_passes_but_should_not():
    try:
        x = 1 / 1
        assert False
    except Exception:
        assert True

# Even if the appropriate exception is caught, it is bad style,
# because the test result is less informative
# than it would be with pytest.raises(e)
# (it just says pass or fail.)

def test_passes_but_bad_style():
    try:
        x = 1 / 0
        assert False
    except ZeroDivisionError:
        assert True

def test_fails_but_bad_style():
    try:
        x = 1 / 1
        assert False
    except ZeroDivisionError:
        assert True

उत्पादन

============================================================================================= test session starts ==============================================================================================
platform linux2 -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4
collected 7 items 

test.py ..FF..F

=================================================================================================== FAILURES ===================================================================================================
__________________________________________________________________________________________________ test_fails __________________________________________________________________________________________________

    def test_fails():
        with pytest.raises(Exception) as e_info:
>           x = 1 / 1
E           Failed: DID NOT RAISE

test.py:13: Failed
___________________________________________________________________________________________ test_fails_without_info ____________________________________________________________________________________________

    def test_fails_without_info():
        with pytest.raises(Exception):
>           x = 1 / 1
E           Failed: DID NOT RAISE

test.py:17: Failed
___________________________________________________________________________________________ test_fails_but_bad_style ___________________________________________________________________________________________

    def test_fails_but_bad_style():
        try:
            x = 1 / 1
>           assert False
E           assert False

test.py:43: AssertionError
====================================================================================== 3 failed, 4 passed in 0.02 seconds ======================================================================================

ध्यान दें कि e_infoअपवाद ऑब्जेक्ट को सहेजता है ताकि आप उससे विवरण निकाल सकें। उदाहरण के लिए, यदि आप अपवाद कॉल स्टैक या किसी अन्य नेस्टेड अपवाद की जाँच करना चाहते हैं।


35
यह अच्छा होगा यदि आप वास्तव में क्वेरी करते हुए एक उदाहरण शामिल कर सकते हैं e_info। कुछ अन्य भाषाओं के साथ अधिक परिचित डेवलपर्स के लिए, यह स्पष्ट नहीं है कि ब्लॉक के e_infoबाहर फैली हुई है with
cjs

153

क्या आपका मतलब कुछ इस तरह का था:

def test_raises():
    with pytest.raises(Exception) as execinfo:   
        raise Exception('some info')
    # these asserts are identical; you can use either one   
    assert execinfo.value.args[0] == 'some info'
    assert str(execinfo.value) == 'some info'

16
excinfo.value.messageमेरे लिए काम नहीं किया, का उपयोग करना पड़ा str(excinfo.value), एक नया जवाब जोड़ा
d_j

5
@d_j, मैसेज assert excinfo.value.args[0] == 'some info'को एक्सेस करने का सीधा तरीका है
मैक्स्चलेज़िग

assert excinfo.match(r"^some info$")के रूप में अच्छी तरह से काम करता है
रॉबिन नेमेथ

14
संस्करण के बाद से 3.1आप कीवर्ड तर्क matchका उपयोग यह दावा करने के लिए कर सकते हैं कि अपवाद एक पाठ या regex से मेल खाता है: with raises(ValueError, match='must be 0 or None'): raise ValueError("value must be 0 or None")याwith raises(ValueError, match=r'must be \d+$'): raise ValueError("value must be 42")
Ilya Rusin

58

पाइस्टेस्ट में इस तरह के मामलों को संभालने के दो तरीके हैं:

  • pytest.raisesफ़ंक्शन का उपयोग करना

  • pytest.mark.xfailडेकोरेटर का उपयोग करना

का उपयोग pytest.raises:

def whatever():
    return 9/0
def test_whatever():
    with pytest.raises(ZeroDivisionError):
        whatever()

का उपयोग pytest.mark.xfail:

@pytest.mark.xfail(raises=ZeroDivisionError)
def test_whatever():
    whatever()

का आउटपुट pytest.raises:

============================= test session starts ============================
platform linux2 -- Python 2.7.10, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- 
/usr/local/python_2.7_10/bin/python
cachedir: .cache
rootdir: /home/user, inifile:
collected 1 item

test_fun.py::test_whatever PASSED


======================== 1 passed in 0.01 seconds =============================

pytest.xfailमार्कर का आउटपुट :

============================= test session starts ============================
platform linux2 -- Python 2.7.10, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- 
/usr/local/python_2.7_10/bin/python
cachedir: .cache
rootdir: /home/user, inifile:
collected 1 item

test_fun.py::test_whatever xfail

======================== 1 xfailed in 0.03 seconds=============================

जैसा कि प्रलेखन कहता है:

उपयोग करना pytest.raisesउन मामलों के लिए बेहतर होने की संभावना है जहां आप अपवादों का परीक्षण कर रहे हैं, अपने स्वयं के कोड को जानबूझकर बढ़ा रहे हैं, जबकि @pytest.mark.xfailचेक फ़ंक्शन के साथ उपयोग करना संभवतः कुछ के लिए बेहतर है जैसे कि अनफिक्स बग्स (जहां परीक्षण का वर्णन है कि "क्या होना चाहिए" या निर्भरता में बग) ।


xfailयहाँ समस्या का समाधान नहीं है, यह परीक्षण को विफल करने की अनुमति देता है। यदि हम एक निश्चित अपवाद को उठाते हैं, तो हम यहाँ जाँच करना चाहेंगे।
Ctrl-C

44

तुम कोशिश कर सकते हो

def test_exception():
    with pytest.raises(Exception) as excinfo:   
        function_that_raises_exception()   
    assert str(excinfo.value) == 'some info' 

Pytest 5.0.0 में एक स्ट्रिंग के रूप में अपवाद संदेश / मूल्य प्राप्त करने के लिए, का उपयोग str(excinfo.value)करना आवश्यक है। यह pytest 4.x में भी काम करता है। Pytest 4.x में str(excinfo)भी काम करता है, लेकिन pytest 5.0.0 में काम नहीं करता है ।
मकेन

यह वही है जिसे मैं देख रहा था। धन्यवाद
एस्तेन बाय बाय

15

पाइस्टेस्ट लगातार विकसित होता है और हाल के दिनों में एक अच्छे बदलाव के साथ अब एक साथ परीक्षण करना संभव है

  • अपवाद प्रकार (सख्त परीक्षण)
  • त्रुटि संदेश (सख्त या ढीली जाँच एक नियमित अभिव्यक्ति का उपयोग करके)

प्रलेखन से दो उदाहरण:

with pytest.raises(ValueError, match='must be 0 or None'):
    raise ValueError('value must be 0 or None')
with pytest.raises(ValueError, match=r'must be \d+$'):
    raise ValueError('value must be 42')

मैं कई परियोजनाओं में उस दृष्टिकोण का उपयोग कर रहा हूं और इसे बहुत पसंद करता हूं।


6

सही तरीका उपयोग कर pytest.raisesरहा है, लेकिन मुझे यहाँ टिप्पणियों में दिलचस्प वैकल्पिक तरीका मिला और मैं इस प्रश्न के भविष्य के पाठकों के लिए इसे सहेजना चाहता हूं:

try:
    thing_that_rasises_typeerror()
    assert False
except TypeError:
    assert True


2

बेहतर अभ्यास एक ऐसे वर्ग का उपयोग करेगा जो विरासत में मिले ।estCase और self.assertRaises को चला रहा है।

उदाहरण के लिए:

import unittest


def whatever():
    return 9/0


class TestWhatEver(unittest.TestCase):

    def test_whatever():
        with self.assertRaises(ZeroDivisionError):
            whatever()

तब आप इसे चलाकर निष्पादित करेंगे:

pytest -vs test_path

4
क्या की तुलना में बेहतर अभ्यास? मैं बिल्कुल भी सिंटैक्स "बेहतर अभ्यास" के बजाय एकतरफा सिंटैक्स का उपयोग नहीं करूंगा।
जीन-फ्रांस्वा कॉर्बेट

2
यह 'बेहतर' नहीं हो सकता है, लेकिन यह एक उपयोगी विकल्प है। क्योंकि एक उत्तर की कसौटी उपयोगिता है, मैं उत्थान कर रहा हूँ।
Reb.Cabin

की तरह लग रहा pytestहै और अधिक लोकप्रिय है nosex, लेकिन यह है कि मैं कैसे pytest का उपयोग करें।
गैंग

0

क्या आपने "pytrace = True" को हटाने की कोशिश की है?

pytest.fail(exc, pytrace=True) # before
pytest.fail(exc) # after

क्या आपने '--फुलट्रेस' के साथ चलने की कोशिश की है?

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