python - आप कैसे परीक्षण करते हैं कि एक पायथन फ़ंक्शन अपवाद फेंकता है?




unit-testing exception (8)

आप कैसे परीक्षण करते हैं कि एक पायथन फ़ंक्शन अपवाद फेंकता है?

कोई एक परीक्षण कैसे लिखता है जो केवल तभी विफल रहता है जब कोई फ़ंक्शन अपेक्षित अपवाद नहीं फेंकता है?

संक्षिप्त जवाब:

एक संदर्भ प्रबंधक के रूप में self.assertRaises विधि का उपयोग करें:

    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'

प्रदर्शन

पाइथन शेल में प्रदर्शन करने के लिए सबसे अच्छा अभ्यास दृष्टिकोण काफी आसान है।

सबसे unittest पुस्तकालय

पायथन 2.7 या 3 में:

import unittest

पायथन 2.6 में, आप 2.7 की unittest लाइब्रेरी का बैकपोर्ट इंस्टॉल कर सकते हैं, जिसे unittest2 कहा जाता है, और केवल उपनाम जो कि सबसे unittest :

import unittest2 as unittest

उदाहरण परीक्षण

अब, पाइथन के प्रकार-सुरक्षा के निम्नलिखित परीक्षण में अपने पायथन शेल में पेस्ट करें:

class MyTestCase(unittest.TestCase):
    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'
    def test_2_cannot_add_int_and_str(self):
        import operator
        self.assertRaises(TypeError, operator.add, 1, '1')

परीक्षण एक संदर्भ प्रबंधक के रूप में assertRaises का उपयोग करता है, जो सुनिश्चित करता है कि दर्ज की गई है, जबकि त्रुटि ठीक से पकड़ा और साफ़ किया गया है।

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

मुझे लगता है कि संदर्भ प्रबंधक का उपयोग करने के लिए यह कहीं अधिक सरल, पठनीय और रखरखाव योग्य है।

परीक्षण चल रहा है

परीक्षण चलाने के लिए:

unittest.main(exit=False)

पायथन 2.6 में, आपको शायद निम्न की आवश्यकता होगी :

unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

और आपके टर्मिनल को निम्नलिखित आउटपुट करना चाहिए:

..
----------------------------------------------------------------------
Ran 2 tests in 0.007s

OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>

और हम देखते हैं कि जैसा कि हम उम्मीद करते हैं, टाइप 1 एक 1 और '1' परिणाम जोड़ने का प्रयास करते हैं।

अधिक वर्बोज आउटपुट के लिए, इसे आजमाएं:

unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

एक व्यक्ति एक अनजान कैसे लिखता है जो केवल तभी विफल रहता है जब कोई फ़ंक्शन अपेक्षित अपवाद नहीं फेंकता है?


अपवाद उठाया गया था या नहीं, यह जांचने के लिए आप अपना खुद का संदर्भ contextmanager बना सकते हैं।

import contextlib

@contextlib.contextmanager
def raises(exception):
    try:
        yield 
    except exception as e:
        assert True
    else:
        assert False

और फिर आप इस तरह के raises उपयोग कर सकते हैं:

with raises(Exception):
    print "Hola"  # Calls assert False

with raises(Exception):
    raise Exception  # Calls assert True

यदि आप pytest का उपयोग कर रहे हैं, तो यह बात पहले से ही लागू की गई है। आप pytest.raises(Exception) कर सकते हैं:

उदाहरण:

def test_div_zero():
    with pytest.raises(ZeroDivisionError):
        1/0

और नतीजा:

[email protected]$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items 

tests/test_div_zero.py:6: test_div_zero PASSED

आपके कोड को इस पैटर्न का पालन करना चाहिए (यह एक unittest मॉड्यूल शैली परीक्षण है):

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except Exception as e:
       self.fail('Unexpected exception raised:', e)
    else:
       self.fail('ExpectedException not raised')

पायथन <2.7 पर यह निर्माण अपेक्षित अपवाद में विशिष्ट मानों की जांच के लिए उपयोगी है। assertRaises फ़ंक्शन assertRaises केवल तभी जांचता है जब कोई अपवाद उठाया गया हो।


चूंकि पायथन 2.7 आप वास्तविक अपवाद वस्तु को फेंकने के लिए संदर्भ प्रबंधक का उपयोग कर सकते हैं:

import unittest

def broken_function():
    raise Exception('This is broken')

class MyTestCase(unittest.TestCase):
    def test(self):
        with self.assertRaises(Exception) as context:
            broken_function()

        self.assertTrue('This is broken' in context.exception)

if __name__ == '__main__':
    unittest.main()

http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises

पायथन 3.5 में , आपको context.exception को str में लपेटना होगा, अन्यथा आपको TypeError मिल जाएगा

self.assertTrue('This is broken' in str(context.exception))

मैं लगभग हर जगह सबसे व्यावहारिक [1] का उपयोग करता हूं क्योंकि मुझे यह तथ्य पसंद है कि मैं एक ही समय में अपने कार्यों को दस्तावेज और परीक्षण करता हूं।

इस कोड को देखें:

def throw_up(something, gowrong=False):
    """
    >>> throw_up('Fish n Chips')
    Traceback (most recent call last):
    ...
    Exception: Fish n Chips

    >>> throw_up('Fish n Chips', gowrong=True)
    'I feel fine!'
    """
    if gowrong:
        return "I feel fine!"
    raise Exception(something)

if __name__ == '__main__':
    import doctest
    doctest.testmod()

यदि आप इस उदाहरण को मॉड्यूल में रखते हैं और इसे कमांड लाइन से चलाते हैं तो दोनों परीक्षण मामलों का मूल्यांकन और जांच की जाती है।

[1] पायथन दस्तावेज: 23.2 सिद्धांत - परीक्षण इंटरैक्टिव पायथन उदाहरण


मैंने अभी पाया है कि मॉक लाइब्रेरी एक assertRaisesWithMessage () विधि प्रदान करता है (इसके unittest.TestCase subclass में), जो न केवल अपेक्षित अपवाद उठाया जाएगा, बल्कि यह भी अपेक्षित संदेश के साथ उठाया जाएगा:

from testcase import TestCase

import mymod

class MyTestCase(TestCase):
    def test1(self):
        self.assertRaisesWithMessage(SomeCoolException,
                                     'expected message',
                                     mymod.myfunc)


Unittest मॉड्यूल से TestCase.assertRaises (या TestCase.failUnlessRaises ) का उपयोग करें, उदाहरण के लिए:

import mymod

class MyTestCase(unittest.TestCase):
    def test1(self):
        self.assertRaises(SomeCoolException, mymod.myfunc)




exception-handling