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


जवाबों:


679

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

import mymod

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

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

67
ध्यान दें कि आपके पास तर्कों को पास myfuncकरने के लिए उन्हें तर्क के रूप में जोड़ने की आवश्यकता है, जैसे कि कॉल। देखें डेरिल स्पिट्जर का जवाब।
cbron

1
क्या कई अपवाद प्रकारों के लिए अनुमति देने का एक तरीका है?
दिनेश

1
आप जोर से परखने के लिए पायथन के बिल्ट-इन अपवादों का उपयोग कर सकते हैं; उदाहरण के लिए @ Moe के उत्तर का उपयोग करना self.assertRaises(TypeError, mymod.myfunc):। आप यहाँ अंतर्निहित अपवादों की पूरी सूची पा सकते हैं: docs.python.org/3/library/exception.html#bltin-exception
रेमंड

3
वर्ग self.assertRaises(SomeCoolException, Constructor, arg1)
रचनाकारों के

475

पायथन 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))

6
मैं पायथन 2.7.10 का उपयोग कर रहा हूं, और ऊपर काम नहीं करता है; context.exceptionसंदेश नहीं देता; यह एक प्रकार है।
स्वर्गीय कोड

6
पायथन 2.7 में भी (कम से कम मेरे 2.7.6 में) का उपयोग करते हुए import unittest2, आपको उपयोग करने की आवश्यकता है str(), अर्थात self.assertTrue('This is broken' in str(context.exception))
सोहेल सी

4
दो बातें: 1. आप जोर के बजाय assertIn का उपयोग कर सकते हैं। उदा। Self.assertIn ('यह टूट गया है', reference.exception) 2. मेरे मामले में, 2.7.10 का उपयोग करके, reference.exception वर्णों का एक सरणी प्रतीत होता है। Str का उपयोग करने से काम नहीं चलता है। मैंने यह करना समाप्त कर दिया: '' .जॉइन (संदर्भ.बोध) इसलिए, एक साथ रखें: self.assertIn ('यह टूट गया है', '' .join (संदर्भ.सेक्स))
ब्लॉकशीप

1
क्या यह सामान्य है कि आपकी विधि अपवाद के ट्रैसबैक के साथ परीक्षण कंसोल को रोकती है? मैं ऐसा होने से कैसे रोकूं?
MadPhysicist

1
बाद में मुझे संदेश को अपवाद के रूप में प्राप्त करने का एक और तरीका मिला, यह गलत है = reference.exception.message। और फिर टेस्ट करने के लिए self.assertEqual (ग़लती, 'यह टूट गया है') का उपयोग कर सकते हैं।
झिहंग

326

मेरे पिछले उत्तर के कोड को सरल बनाया जा सकता है:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction)

और अगर तर्कों में तर्क होते हैं, तो उन्हें इस तरह से मुखर कर दें:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction, arg1, arg2)

17
जब तर्क पारित किया जाता है तो वास्तव में मददगार होने के बारे में दूसरा स्निप।
सब्यसाची

मैं उपयोग कर रहा हूं 2.7.15। अगर afunctionमें self.assertRaises(ExpectedException, afunction, arg1, arg2)वर्ग प्रारंभकर्ता है, तो आप उत्तीर्ण करने की आवश्यकता selfपहला तर्क जैसे, के रूप में self.assertRaises(ExpectedException, Class, self, arg1, arg2)
मिन्ह ट्रॅन

128

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

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

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

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लाइब्रेरी का बैकपोर्ट स्थापित कर सकते हैं , जिसे यूनिटेस्ट 2 कहा जाता है , और सिर्फ उर्फ 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'एक में परिणाम TypeError


अधिक वर्बोज़ आउटपुट के लिए, यह आज़माएँ:

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

56

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

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except Exception:
       self.fail('unexpected exception raised')
    else:
       self.fail('ExpectedException not raised')

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


3
और विधि self.fail केवल एक तर्क लेता है
mdob

3
यदि परीक्षण किसी अपवाद को छोड़ता है तो यह परीक्षण के लिए अत्यधिक जटिल लगता है। चूँकि उस अपवाद के अलावा कोई भी अपवाद परीक्षण में त्रुटि करेगा और अपवाद को न फेंकना परीक्षण को विफल कर देगा, ऐसा लगता है कि एकमात्र अंतर यह है कि यदि आप एक अलग अपवाद प्राप्त करते हैं तो आपको assertRaisesFAIL के बजाय ERROR मिलेगा।
अनफॉलो

24

से: http://www.lengrand.fr/2011/12/pythununestest-assertraises-raises-error/

सबसे पहले, यहाँ फ़ाइल dum_function.py में संबंधित (अभी भी डम: पी) फ़ंक्शन है:

def square_value(a):
   """
   Returns the square value of a.
   """
   try:
       out = a*a
   except TypeError:
       raise TypeError("Input should be a string:")

   return out

यहाँ परीक्षण किया जाना है (केवल यह परीक्षण डाला गया है):

import dum_function as df # import function module
import unittest
class Test(unittest.TestCase):
   """
      The class inherits from unittest
      """
   def setUp(self):
       """
       This method is called before each test
       """
       self.false_int = "A"

   def tearDown(self):
       """
       This method is called after each test
       """
       pass
      #---
         ## TESTS
   def test_square_value(self):
       # assertRaises(excClass, callableObj) prototype
       self.assertRaises(TypeError, df.square_value(self.false_int))

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

अब हम अपने कार्य का परीक्षण करने के लिए तैयार हैं! परीक्षण चलाने की कोशिश करने पर ऐसा होता है:

======================================================================
ERROR: test_square_value (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_dum_function.py", line 22, in test_square_value
    self.assertRaises(TypeError, df.square_value(self.false_int))
  File "/home/jlengrand/Desktop/function.py", line 8, in square_value
    raise TypeError("Input should be a string:")
TypeError: Input should be a string:

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

TypeError actullay उठाया है, और एक परीक्षण विफलता उत्पन्न करता है। समस्या यह है कि यह ठीक वैसा ही व्यवहार है जैसा हम चाहते थे: एस।

इस त्रुटि से बचने के लिए, परीक्षण कॉल में लंबो का उपयोग करके फ़ंक्शन को चलाएं:

self.assertRaises(TypeError, lambda: df.square_value(self.false_int))

अंतिम आउटपुट:

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

उत्तम !

... और मेरे लिए भी सही है !!

बहुत बहुत धन्यवाद श्री जूलियन लेनग्रैंड-लैंबर्ट


यह परीक्षण वास्तव में एक गलत सकारात्मक रिटर्न देता है । ऐसा इसलिए होता है क्योंकि 'assertRaises' के अंदर का लंबोदर वह इकाई है जो टाइप त्रुटि उठाती है, कि परीक्षणित फ़ंक्शन।


10
बस एक नोट, आपको लैम्ब्डा की जरूरत नहीं है। लाइन self.assertRaises(TypeError, df.square_value(self.false_int))विधि को कॉल करती है और परिणाम लौटाती है। आप जो चाहते हैं वह विधि और किसी भी तर्क को पारित करने के लिए है और इसे कॉल करने के लिए self.assertRaises(TypeError, df.square_value, self.false_int)
एकजुट होने

बहुत बहुत धन्यवाद। पूरी तरह से काम करता है
चंदन कुमार

14

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

और परिणाम:

pigueiras@pigueiras$ 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

1
unittestमॉड्यूल की आवश्यकता नहीं है कि एक जवाब पोस्ट करने के लिए धन्यवाद !
शेरवुड कॉलवे

10

मैं लगभग हर जगह सिद्धांत [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()

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

[१] पायथन प्रलेखन: २३.२ सिद्धांत - टेस्ट इंटरैक्टिव पायथन उदाहरण


4
मैं सिद्धांत से प्यार करता हूं, लेकिन मैं इसे अनुपयोगी की जगह अनुपूरक पाता हूं।
टिमोथीविसमैन

2
क्या स्वत: रीफैक्टरिंग के साथ अच्छा खेलने की संभावना कम है? मुझे लगता है कि अजगर के लिए डिज़ाइन किया गया एक रीफैक्टरिंग उपकरण डॉकस्ट्रिंग्स के बारे में पता होना चाहिए। क्या कोई उनके अनुभव से टिप्पणी कर सकता है?
kdbanman

6

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

from testcase import TestCase

import mymod

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

दुर्भाग्य से, यह अब और प्रदान नहीं करता है .. लेकिन @Art ( stackoverflow.com/a/3166985/1504046 ) का उपरोक्त उत्तर समान परिणाम देता है
Rmatt

6

यहाँ बहुत सारे उत्तर हैं। कोड दिखाता है कि हम एक अपवाद कैसे बना सकते हैं, हम अपने तरीकों में उस अपवाद का उपयोग कैसे कर सकते हैं, और अंत में, आप इकाई परीक्षण में कैसे सत्यापित कर सकते हैं, सही अपवाद उठाए जा रहे हैं।

import unittest

class DeviceException(Exception):
    def __init__(self, msg, code):
        self.msg = msg
        self.code = code
    def __str__(self):
        return repr("Error {}: {}".format(self.code, self.msg))

class MyDevice(object):
    def __init__(self):
        self.name = 'DefaultName'

    def setParameter(self, param, value):
        if isinstance(value, str):
            setattr(self, param , value)
        else:
            raise DeviceException('Incorrect type of argument passed. Name expects a string', 100001)

    def getParameter(self, param):
        return getattr(self, param)

class TestMyDevice(unittest.TestCase):

    def setUp(self):
        self.dev1 = MyDevice()

    def tearDown(self):
        del self.dev1

    def test_name(self):
        """ Test for valid input for name parameter """

        self.dev1.setParameter('name', 'MyDevice')
        name = self.dev1.getParameter('name')
        self.assertEqual(name, 'MyDevice')

    def test_invalid_name(self):
        """ Test to check if error is raised if invalid type of input is provided """

        self.assertRaises(DeviceException, self.dev1.setParameter, 'name', 1234)

    def test_exception_message(self):
        """ Test to check if correct exception message and code is raised when incorrect value is passed """

        with self.assertRaises(DeviceException) as cm:
            self.dev1.setParameter('name', 1234)
        self.assertEqual(cm.exception.msg, 'Incorrect type of argument passed. Name expects a string', 'mismatch in expected error message')
        self.assertEqual(cm.exception.code, 100001, 'mismatch in expected error code')


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

3

आप unittest मॉड्यूल से assertRaises का उपयोग कर सकते हैं

import unittest

class TestClass():
  def raises_exception(self):
    raise Exception("test")

class MyTestCase(unittest.TestCase):
  def test_if_method_raises_correct_exception(self):
    test_class = TestClass()
    # note that you dont use () when passing the method to assertRaises
    self.assertRaises(Exception, test_class.raises_exception)

-5

हालांकि सभी उत्तर पूरी तरह से ठीक हैं, मैं परीक्षण करने का एक तरीका ढूंढ रहा था कि क्या एक फ़ंक्शन ने यूनिट परीक्षण रूपरेखाओं पर भरोसा किए बिना और परीक्षण कक्षाएं लिखने के लिए बिना अपवाद उठाया।

मैंने निम्नलिखित लिखना समाप्त किया:

def assert_error(e, x):
    try:
        e(x)
    except:
        return
    raise AssertionError()

def failing_function(x):
    raise ValueError()

def dummy_function(x):
    return x

if __name__=="__main__":
    assert_error(failing_function, 0)
    assert_error(dummy_function, 0)

और यह सही लाइन पर विफल रहता है:

Traceback (most recent call last):
  File "assert_error.py", line 16, in <module>
    assert_error(dummy_function, 0)
  File "assert_error.py", line 6, in assert_error
    raise AssertionError()
AssertionError
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.