itsource

Python 함수가 예외를 발생시키는 것을 어떻게 테스트합니까?

mycopycode 2023. 2. 6. 23:32
반응형

Python 함수가 예외를 발생시키는 것을 어떻게 테스트합니까?

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

사용(또는TestCase.failUnlessRaisesunittest 모듈의 예를 들어 다음과 같습니다.

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


Python 3.5에서는 랩을 해야 합니다.context.exceptionstr 않으면, '아예'가TypeError

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

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

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

함수에서 인수를 받는 경우 다음과 같이 assertRaises에 인수를 전달합니다.

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

Python 함수가 예외를 발생시키는 것을 어떻게 테스트합니까?

함수가 예상된 예외를 발생시키지 않는 경우에만 실패한 테스트를 어떻게 작성할 수 있습니까?

단답:

하다를 사용하세요.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

2.2.7 의 Python 2.6 의 백 할 수 .unittest라이브러리, unittest2라고 불리며 에일리어스만 지정됩니다.unittest:

import unittest2 as unittest

테스트 예시

이제 Python 쉘에 Python의 type-safety에 대한 다음 테스트를 붙여넣습니다.

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를 참조해 주세요.첫 번째 인수는 예상되는 오류 유형, 두 번째 인수는 테스트 중인 함수이며 나머지 arg 및 키워드 arg는 해당 함수에 전달됩니다.

콘텍스트 매니저를 사용하는 것만으로, 훨씬 심플하고, 읽기 쉽고, 유지보수가 용이하다고 생각합니다.

테스트 실행

테스트를 실행하려면:

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>

우리가한 대로, ''를 더하려고 '우리'는 '우리'1 a. a. a.'1'TypeError.


자세한 출력은 다음과 같습니다.

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

코드는 다음 패턴을 따라야 합니다(이것은 가장 짧은 모듈 스타일 테스트입니다).

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 에서는, 이 구성은, 예상되는 예외의 특정의 값을 체크하는데 도움이 됩니다. " " "assertRaises는 예외가 발생했는지 여부만 확인합니다.

출처 : http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/

먼저 file dum_function에 대응하는 (still dum:p) 함수를 나타냅니다.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가 발생하며 테스트 실패가 발생합니다.문제는 이것이 바로 우리가 원했던 동작이라는 것입니다:s.

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

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

최종 출력은 다음과 같습니다.

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

OK

완벽해!

그리고 나도 완벽해!!

쥴리엔 렌그랑 람버트 씨


이 테스트 어설트는 실제로 잘못된 양성을 반환합니다.이 문제는 'AssertRaises' 내부의 람다가 유형 오류를 일으키는 단위이기 때문에 발생하며 테스트된 함수가 아니기 때문입니다.

콘텍스트 매니저를 사용하여 접수된 리스트 중 특정 예외가 발생했는지 확인하는 방법에 대한 자세한 설명을 보지 못했기 때문에 제 예외를 추가합니다(python 3.8에서 확인).

를 그 TypeError나는 다음과 같이 쓰고 싶다.

with self.assertRaises(TypeError):
    function_raising_some_exception(parameters)

TypeError ★★★★★★★★★★★★★★★★★」IndexError나는 다음과 같이 쓰고 싶다.

with self.assertRaises((TypeError,IndexError)):
    function_raising_some_exception(parameters)

또한 발생한 예외에 대해 더 자세히 알고 싶다면 다음과 같은 맥락에서 파악할 수 있습니다.

# Here I catch any exception    
with self.assertRaises(Exception) as e:
    function_raising_some_exception(parameters)

# Here I check actual exception type (but I could
# check anything else about that specific exception,
# like it's actual message or values stored in the exception)
self.assertTrue(type(e.exception) in [TypeError,MatrixIsSingular])

「 」를 사용하고 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

직접 .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

3 를 그 메시지와 Python 3 을 사용할 수 .assertRaisesmsg키워드 인수는 다음과 같습니다.

import unittest

def your_function():
    raise RuntimeError('your exception message')

class YourTestCase(unittest.TestCase):
    def test(self):
        with self.assertRaises(RuntimeError, msg='your exception message'):
            your_function()


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

문서화와 기능을 동시에 테스트하기 때문에 거의 모든 곳에서 doctest[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] Python 문서: 23.2 doctest -- 대화형 Python 예제 테스트

여기 정답이 많네요.코드는 예외를 생성하는 방법, 메서드에서 예외를 사용하는 방법, 마지막으로 유닛 테스트에서 올바른 예외가 발생하는지 확인하는 방법을 보여 줍니다.

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

는 방금 모크 라이브러리가 assertRaises를 제공한다는 것을 알았다.With Message() 메서드(unittest).TestCase 서브클래스)는 예상된 예외가 발생했는지 여부뿐만 아니라 예상된 메시지와 함께 발생했는지 확인합니다.

from testcase import TestCase

import mymod

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

가장 짧은 모듈에서 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)

Django에 있는 사용자의 경우 컨텍스트 매니저를 사용하여 장애가 발생한 함수를 실행하고 다음 명령을 사용하여 특정 메시지에서 예외를 발생시킬 수 있습니다.assertRaisesMessage

with self.assertRaisesMessage(SomeException,'Some error message e.g 404 Not Found'):
    faulty_funtion()

대기/비동기 테스트에는 약간 다른 패턴이 있습니다.

https://aiounittest.readthedocs.io/en/latest/asynctestcase.html#aiounittest.AsyncTestCase

async def test_await_async_fail(self):
    with self.assertRaises(Exception) as e:
        await async_one()

이 클래스에서는 stock_id를 Integer로 설정하면 TypeError가 발생합니다.이러한 경우 테스트는 통과하고 그렇지 않으면 실패합니다.

def set_string(prop, value):
   if not isinstance(value, str):
      raise TypeError("i told you i take strings only ")
   return value

class BuyVolume(ndb.Model):
    stock_id = ndb.StringProperty(validator=set_string)

from pytest import raises
buy_volume_instance: BuyVolume = BuyVolume()
with raises(TypeError):
  buy_volume_instance.stock_id = 25

unittest를 사용한 유닛테스트가 권장되지만 빠른 수정을 원하는 경우 예외를 포착하여 변수에 할당하고 해당 변수가 해당 예외 클래스의 인스턴스인지 여부를 확인할 수 있습니다.

불량 함수가 ValueError를 발생시킨다고 가정합니다.

    try:
      bad_function()
    except ValueError as e:
      assert isinstance(e, ValueError)

다음 4가지 옵션이 있습니다(결국 전체 예제를 참조할 수 있습니다).

assert 컨텍스트 관리자를 사용하여 상승

def test_raises(self):
    with self.assertRaises(RuntimeError):
        raise RuntimeError()

assert 한 줄씩 올립니다.

주의: 함수 호출 대신 함수를 호출 가능(둥근 괄호 없음)으로 사용합니다.

def test_raises(self):
    self.assertRaises(RuntimeError, your_function)

assertRaisesRegex 와 컨텍스트 매니저의

두 번째 파라미터는 regex expression으로 필수입니다.예외 메시지를 확인하려면 이 옵션을 사용해야 합니다.

def test_raises_regex(self):
    with self.assertRaisesRegex(RuntimeError, r'.* exception message'):
        raise RuntimeError('your exception message')

assertRaisesRegex 원라이너

두 번째 파라미터는 regex expression으로 필수입니다.예외 메시지를 확인하려면 이 옵션을 사용해야 합니다.

주의: 함수 호출 대신 함수를 호출 가능(둥근 괄호 없음)으로 사용합니다.

def test_raises_regex(self):
    self.assertRaisesRegex(RuntimeError, r'.* exception message', your_function)

풀 코드 예시:

import unittest

def your_function():
    raise RuntimeError('your exception message')

class YourTestCase(unittest.TestCase):

    def test_1_raises_context_manager(self):
        with self.assertRaises(RuntimeError):
            your_function()

    def test_2_raises_oneliner(self):
        self.assertRaises(RuntimeError, your_function)

    def test_3_raises_regex_context_manager(self):
        with self.assertRaisesRegex(RuntimeError, r'.* exception message'):
            your_function()

    def test_4_raises_regex_oneliner(self):
        self.assertRaisesRegex(RuntimeError, r'.* exception message', your_function)

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

어떤 스타일을 따를지는 개발자에 따라 다르지만 콘텍스트 매니저를 사용하는 두 가지 방법을 모두 선호합니다.

모든 답변이 완벽하지만 단위 테스트 프레임워크에 의존하지 않고 테스트 클래스를 작성하지 않고 함수가 예외를 발생시켰는지 테스트하는 방법을 찾고 있었습니다.

나는 다음과 같은 글을 쓰게 되었다.

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

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

반응형