Python 어설션 예외

Neema Muganga 2023년10월10일
  1. 컨텍스트 관리자를 사용하여 Python Assert 예외 포착
  2. 키워드 인수를 사용하여 Python Assert 예외 잡기
Python 어설션 예외

이 기사는 함수가 반드시 실행을 종료하지 않고도 예외(코드 실행 중에 감지된 오류)를 던질 수 있는지 테스트하기 위해 테스트 단위로서의 assert에 대한 이해를 제공합니다. 즉, 던져진 예외는 캡슐화됩니다.

이 테스트는 예외가 발생하면 통과합니다. 예상한 것과 다른 예외가 발생하면 오류가 발생합니다. 발생한 예외가 전혀 없는 경우 테스트가 실패합니다.

컨텍스트 관리자를 사용하여 Python Assert 예외 포착

일반적인 파이썬 개념에서 필연적으로 필요할 때 리소스 할당 및 해제를 허용하는 방법과 유사하게 여기 컨텍스트는 테스트 중에 던져지는 실제 예외 객체를 보유한다.

발생한 예외에 대한 추가 성능 검사가 필요한 경우 이 예외 속성을 개체에 저장합니다.

예외가 발생했는지 여부에 관계없이 함수가 실패하거나 통과하는지 테스트하기 위해 unittest 모듈에서 TestCase.assertRaises를 사용합니다.

컨텍스트 관리자를 사용하는 실제 예를 살펴보겠습니다.

import unittest


class TestCase(unittest.TestCase):
    def test_nameerror(self):
        with self.assertRaises(Exception):
            100 * (someNumber / 5)


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

출력:

.
----------------------------------------------------------------------
Ran 1 test in 0.002s

OK

예제 코드에서는 예외가 throw될 것으로 예상하기 때문에 테스트가 통과합니다. 5를 정의되지 않은 변수 someNumber로 나눕니다. 따라서 함수는 NameError 예외를 발생시킵니다. 따라서 우리의 테스트는 출력의 첫 번째 줄에 .로 표시된 대로 통과합니다.

예외가 발생하지 않을 때 테스트가 실패하는 예를 살펴보겠습니다.

import unittest


class TestCase(unittest.TestCase):
    def test_nameerror(self):
        with self.assertRaises(Exception):
            someNumber = 10
            100 * (someNumber / 5)


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

출력:

F
======================================================================
FAIL: test_nameerror (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):  File "c:\Users\Neema\Desktop\Article Requirement Spec and Example 
Articles\Article Requirement Spec 
and Example Articles\fah.py", line 106, in test_nameerror
    100 * (someNumber/5)
AssertionError: Exception not raised

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (failures=1)

이 예제 코드에서 someNumber에 대한 값을 정의한 다음 이를 사용하여 산술 표현식을 수행합니다.

출력은 테스트가 예상대로 실패했음을 보여줍니다. someNumber에 대해 정의된 값이 존재하기 때문에 이번에는 NameError 예외가 발생하지 않을 것으로 예상됩니다.

다음 예제와 같이 사용자 정의 예외를 사용하여 컨텍스트 관리자를 구현할 수도 있습니다.

import unittest


def user_function():
    raise Exception("A user-defined exception")


class MyTestCase(unittest.TestCase):
    def test_userexception(self):
        with self.assertRaises(Exception) as context:
            user_function()

        self.assertTrue("A user-defined exception" in str(context.exception))


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

출력:

.
----------------------------------------------------------------------
Ran 1 test in 0.006s

OK

TypeError가 발생하지 않도록 str을 사용하여 context.exception을 묶는 것을 잊지 마십시오.

단위 테스트에서 테스트 값을 true와 비교하는 unittest 라이브러리인 assertTrue를 소개합니다.

assertTrue 대신 assertIn을 사용하도록 선택할 수도 있습니다.

예시:

import unittest


def user_function():
    raise Exception("A use defined exception")


class MyTestCase(unittest.TestCase):
    def test_userexception(self):
        with self.assertRaises(Exception) as context:
            user_function()

        self.assertIn("A use defined exception", str(context.exception))


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

테스트 통과가 생성되는 동일한 출력이 표시됩니다.

키워드 인수를 사용하여 Python Assert 예외 잡기

assertRaises()에만 예외를 전달하는 컨텍스트 관리자와 달리 함수 호출과 함수의 매개변수도 예외를 유발하는 키워드 인수로 전달합니다.

통사론

assertRaises(exception, function, *args, **keywords)

예시:

import unittest


class MyTestCase(unittest.TestCase):
    def test_division_by_error(self):
        import operator

        self.assertRaises(ZeroDivisionError, operator.floordiv, 55, 0)


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

출력:

.
----------------------------------------------------------------------
Ran 1 test in 0.002s

OK

위의 예제 코드는 키워드 인수와 함께 assertRaises()를 사용했습니다. 숫자를 0으로 나누려고 시도한 후 예상되는 ZeroDivisionError 예외를 전달했습니다. floordiv 연산자 함수와 함께 사용되는 연산자 함수를 두 번째 인수로 가져왔습니다. 여기서 매개변수 값은 세 번째 매개변수(55를 0으로 나눈 값)입니다.

assert의 마지막 적용은 예상한 것과 다른 예외를 assertRaise()에 전달할 때입니다. 대신 오류가 생성됩니다.

위에서 사용한 것과 동일한 예제 코드를 사용하여 이것을 구현해 보겠습니다.

import unittest


class MyTestCase(unittest.TestCase):
    def test_division_by_error(self):
        import operator

        self.assertRaises(TypeError, operator.floordiv, 55, 0)


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

출력:

E
======================================================================
ERROR: test_division_by_error (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):  File "c:\Users\Neema\Desktop\Article Requirement Spec and Example 
Articles\user.py", line 16, in test_division_by_error
    self.assertRaises(TypeError, operator.floordiv, 55, 0)
  File "C:\Users\Neema\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 733, in assertRaises
    return context.handle('assertRaises', args, kwargs)
  File "C:\Users\Neema\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 201, in handle
    callable_obj(*args, **kwargs) 
ZeroDivisionError: integer division or modulo by zero

----------------------------------------------------------------------
Ran 1 test in 0.031s

FAILED (errors=1)

출력에서 오류 역추적이 생성됩니다. 숫자를 0으로 나눌 때 ZeroDivisionError 예외가 예상됩니다. 대신, 문자열과 정수와 같은 서로 다른 데이터 유형 간에 산술 연산을 수행할 때 적용되는 TypeError 예외를 전달합니다.

관련 문장 - Python Exception