developer tip

Python 함수에서 예외가 발생하는지 어떻게 테스트합니까?

copycodes 2020. 9. 30. 11:03
반응형

Python 함수에서 예외가 발생하는지 어떻게 테스트합니까?


함수가 예상되는 예외를 발생시키지 않는 경우에만 실패하는 단위 테스트를 어떻게 작성합니까?


unittest 모듈에서 TestCase.assertRaises(또는 TestCase.failUnlessRaises)을 사용 합니다. 예를 들면 다음과 같습니다.

import mymod

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

Python 2.7부터 컨텍스트 관리자를 사용하여 발생한 실제 Exception 객체를 파악할 수 있습니다.

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.exceptionstr, 그렇지 않으면 당신이를 얻을 수 있습니다,TypeError

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

이전 답변의 코드는 다음과 같이 단순화 할 수 있습니다.

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

그리고 afunction이 인수를 받으면 다음과 같이 assertRaises에 전달하십시오.

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

Python 함수에서 예외가 발생하는지 어떻게 테스트합니까?

함수가 예상되는 예외를 throw하지 않는 경우에만 실패하는 테스트를 어떻게 작성합니까?

짧은 답변:

self.assertRaises컨텍스트 관리자로 메소드를 사용하십시오 .

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

데모

모범 사례 접근 방식은 Python 셸에서 쉽게 시연 할 수 있습니다.

unittest라이브러리

Python 2.7 또는 3 :

import unittest

Python 2.6에서는 unittest2unittest 라는 2.7의 라이브러리 백 포트를 설치하고 다음 과 같이 별칭을 지정할 수 있습니다 .unittest

import unittest2 as unittest

예제 테스트

이제 Python의 형식 안전성에 대한 다음 테스트를 Python 셸에 붙여 넣습니다.

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컨텍스트 관리자로 사용 하여 오류가 기록되는 동안 제대로 포착되고 정리되었는지 확인합니다.

컨텍스트 관리자 없이 작성할 수도 있습니다 . 테스트 2를 참조하십시오. 첫 번째 인수는 발생할 것으로 예상되는 오류 유형, 두 번째 인수, 테스트중인 함수, 나머지 인수 및 키워드 args가 해당 함수에 전달됩니다.

컨텍스트 관리자를 사용하는 것이 훨씬 더 간단하고 읽기 쉽고 유지 관리가 가능하다고 생각합니다.

테스트 실행

테스트를 실행하려면 :

unittest.main(exit=False)

Python 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>

그리고 우리가 예상 한대로 a 1'1'결과를 TypeError.


더 자세한 출력을 보려면 다음을 시도하십시오.

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

코드는 다음 패턴을 따라야합니다 (이것은 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')

Python <2.7에서이 구조는 예상되는 예외의 특정 값을 확인하는 데 유용합니다. unittest 함수 assertRaises는 예외가 발생했는지 확인합니다.


에서 : http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/

먼저 dum_function.py 파일의 해당 (여전히 dum : p) 함수가 있습니다.

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가 발생하면 테스트 실패가 발생합니다. 문제는 이것이 우리가 원하는 행동이라는 것입니다.

이 오류를 방지하려면 테스트 호출에서 람다를 사용하여 함수를 실행하면됩니다.

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

최종 출력 :

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

OK

완벽 해!

... 그리고 나에게도 완벽합니다 !!

많이 Thansk Mr. Julien Lengrand-Lambert


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

거의 모든 곳에서 doctest [1]을 사용합니다. 왜냐하면 동시에 내 함수를 문서화하고 테스트한다는 사실이 마음에 들기 때문입니다.

Have a look at this code:

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

If you put this example in a module and run it from the command line both test cases are evaluated and checked.

[1] Python documentation: 23.2 doctest -- Test interactive Python examples


Have a look at the assertRaises method of the unittest module.


I just discovered that the Mock library provides an assertRaisesWithMessage() method (in its unittest.TestCase subclass), which will check not only that the expected exception is raised, but also that it is raised with the expected message:

from testcase import TestCase

import mymod

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

You can use assertRaises from the unittest module

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)

There are a lot of answers here. The code shows how we can create an Exception, how we can use that exception in our methods, and finally, how you can verify in a unittest, the correct exceptions being raised.

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

While all the answers are perfectly fine, I was looking for a way to test if a function raised an exception without relying on unit testing frameworks and having to write test classes.

I ended up writing the following:

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)

And it fails on the right line :

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

참고URL : https://stackoverflow.com/questions/129507/how-do-you-test-that-a-python-function-throws-an-exception

반응형