파이썬 모의 발생 예외
이 문서의 주요 목표는 단위 테스트 라이브러리 unittest
를 사용할 때 예외를 throw하는 방법을 보여 주는 것입니다.
Python에서 단위 테스트 라이브러리 unittest
를 사용할 때 예외 발생
코드가 안정적이고 프로젝트 범위의 대부분의 사용 사례를 설명하는지 확인하려면 다양한 입력을 제공하여 코드를 테스트해야 합니다. Python에 있는 라이브러리 중 하나인 unittest
는 이러한 기능을 제공하여 다른 테스트 사례를 작성하고 수행할 수 있도록 합니다.
테스트하는 동안 입력이 예상치 못한 경우를 처리할 수 있어야 합니다. 주어진 입력에 무엇이 잘못되었는지 자세히 설명하는 예외를 발생시켜 이러한 경우를 처리할 수 있습니다.
다음 코드를 고려하십시오.
class A:
def __init__(self):
pass
def computeData(self):
return 0
class B:
def method_to_test():
obj = A()
try:
print(obj.computeData())
except Exception as e:
print("Exception at method_to_test: " + str(e))
테스트하려는 함수가 method_to_test
라고 가정해 보겠습니다. 다른 클래스 A
의 개체를 초기화한 다음 try-except
블록에서 computeData
라는 메서드 중 하나를 호출하여 예외를 포착합니다.
특정 예외가 발생했을 때 computeData
의 동작을 테스트하려면 unittest
모듈을 사용해야 합니다.
예외를 한 번 발생
위에서 언급한 시나리오를 고려할 때 예외를 throw할 때 더 많은 제어 권한을 갖고 싶은 경우도 있을 수 있습니다.
그러한 요구가 발생할 수 있는 많은 이유가 있을 수 있습니다. 코드 구현에 따라 동작을 더 많이 제어하는 것이 매우 유용할 수 있습니다.
예외 주장
테스트 케이스를 작성하는 동안 예외가 트리거되는지 여부를 확인할 수 있습니다. 이는 예외가 발생했는지 여부를 알고 싶을 때 특히 유용합니다.
이렇게 하면 문제가 발생하는 경우 테스트 사례에서 조기에 발견하는 데 도움이 될 수 있습니다.
모의 타사 모듈
타사 모듈은 구현에 따라 거의 없는 것부터 많은 것까지 다양할 수 있습니다. 타사 모듈이 의도한 대로 작동하는지 테스트하려면 다양한 출력으로 해당 동작을 테스트해야 합니다.
그러한 예 중 하나는 네트워크를 통해 통신하거나 HTTP를 사용하여 데이터를 송수신할 때 널리 사용되는 모듈인 request
입니다.
함수에서 수동으로 예외 발생
computeData
함수에서 수동으로 예외를 발생시키려면 side_effect
속성을 사용해야 합니다.
다음 코드를 고려하십시오.
import unittest
from unittest.mock import patch
from unittest.mock import MagicMock
class A:
def __init__(self) -> None:
pass
def computeData(self):
return 0
class B:
def method_to_test():
obj = A()
try:
print(obj.computeData())
except Exception as e:
print("Exception at method_to_test: " + str(e))
class Test(unittest.TestCase):
@patch.object(A, "computeData", MagicMock(side_effect=Exception("Test")))
def test_method(self):
B.method_to_test()
if __name__ == "__main__":
Test().test_method()
출력:
Exception at method_to_test: Test
솔루션에서 method_to_test
메서드를 테스트하기 위해 새 메서드 test_method
가 생성됩니다. 함수가 patch.object
로 장식되어 있다는 점도 중요합니다.
patch
데코레이터는 모듈 및 클래스 수준 특성을 패치하기 위해 모듈에 제공됩니다. 무엇을 패치할지 구체적으로 설명하기 위해 patch
대신 patch.object
를 사용하여 메서드를 직접 패치합니다.
데코레이터에서 클래스 이름 A
가 전달됩니다. 이는 패치할 개체가 멤버 이름 computeData
가 전달되는 A
의 일부임을 나타냅니다.
마지막 매개변수는 Mock
의 하위 클래스인 MagicMock
개체입니다. 여기에서 side_effect
속성을 사용하여 필요한 동작을 computeData
에 연결합니다. 이 속성은 우리의 경우 예외를 발생시킵니다.
프로그램의 일반적인 흐름은 다음과 같습니다.
test_method
가 호출됩니다.A
클래스의computeData
가 패치됩니다.side_effect
가 할당되는데, 우리의 경우에는 예외입니다.- 클래스
B
의method_to_test
가 호출됩니다. obj
에 저장된 인스턴스와 함께A
클래스의 생성자가 호출됩니다.computeData
가 호출됩니다. 패치 중인 메서드로 인해 예외가 throw됩니다.
한 번 예외 발생
예외를 한 번만 발생시키거나 함수의 동작을 더 많이 제어하기 위해 side_effect
는 단순한 함수 호출 이상을 지원합니다.
현재 side_effect
는 다음을 지원합니다.
반복 가능
호출 가능
예외
(인스턴스 또는 클래스)
Iterable
을 사용하면 예외를 한 번만 발생시키는 메서드를 만들 수 있습니다.
class Test(unittest.TestCase):
@patch.object(A, "computeData", MagicMock(side_effect=[1, Exception("Test"), 3]))
def test_method(self):
B.method_to_test()
if __name__ == "__main__":
testClass = Test()
testClass.test_method()
testClass.test_method()
testClass.test_method()
출력:
1
Exception at method_to_test: Test
3
전달된 Iterable
로 인해 선택한 요소가 패치되고 예외를 발생시킬 시기를 제어할 수 있습니다. 따라서 함수가 두 번째로 호출될 때만 예외가 발생하고 다른 경우에는 1
과 3
이 반환됩니다.
예외 주장
특정 예외가 발생했는지 여부를 확인하려면 원하는 예외가 발생하지 않은 경우 unittest.TestCase.assertRaises
를 사용할 수 있습니다.
class Test(unittest.TestCase):
@patch.object(A, "computeData", MagicMock(side_effect=Exception("Test")))
def test_method(self):
self.assertRaises(KeyError, A.computeData)
if __name__ == "__main__":
Test().test_method()
출력:
Exception at method_to_test: Test
Traceback (most recent call last):
File "d:\Python Articles\a.py", line 28, in <module>
Test().test_method()
File "C:\Program Files\Python310\lib\unittest\mock.py", line 1369, in patched
return func(*newargs, **newkeywargs)
File "d:\Python Articles\a.py", line 25, in test_method
self.assertRaises(KeyError, A.computeData)
File "C:\Program Files\Python310\lib\unittest\case.py", line 738, in assertRaises
return context.handle('assertRaises', args, kwargs)
File "C:\Program Files\Python310\lib\unittest\case.py", line 201, in handle
callable_obj(*args, **kwargs)
File "C:\Program Files\Python310\lib\unittest\mock.py", line 1104, in __call__
return self._mock_call(*args, **kwargs)
File "C:\Program Files\Python310\lib\unittest\mock.py", line 1108, in _mock_call
return self._execute_mock_call(*args, **kwargs)
File "C:\Program Files\Python310\lib\unittest\mock.py", line 1163, in _execute_mock_call
raise effect
File "d:\Python Articles\a.py", line 17, in method_to_test
Exception: Test
두 개의 매개변수로 assertRaises
를 호출하여 test_method
메서드를 약간 변경하여 위의 결과를 얻었습니다.
두 매개변수는 다음과 같이 정의할 수 있습니다.
KeyError
- 트리거하려는 모든 예외가 여기에 전달됩니다.A.computeData
- 예외를 throw해야 하는 메서드입니다.
모의 타사 모듈
이전과 같이 post
를 조롱하려면 patch
데코레이터를 사용해야 합니다. 간단한 예는 다음과 같습니다.
class Test(unittest.TestCase):
@patch(
"requests.post", MagicMock(side_effect=requests.exceptions.ConnectionError())
)
def test_method(self):
requests.post()
출력:
Traceback (most recent call last):
File "d:\Python Articles\a.py", line 33, in <module>
Test().test_method()
File "C:\Program Files\Python310\lib\unittest\mock.py", line 1369, in patched
return func(*newargs, **newkeywargs)
File "d:\Python Articles\a.py", line 30, in test_method
requests.post()
File "C:\Program Files\Python310\lib\unittest\mock.py", line 1104, in __call__
return self._mock_call(*args, **kwargs)
File "C:\Program Files\Python310\lib\unittest\mock.py", line 1108, in _mock_call
return self._execute_mock_call(*args, **kwargs)
File "C:\Program Files\Python310\lib\unittest\mock.py", line 1163, in _execute_mock_call
raise effect
requests.exceptions.ConnectionError
제3자 모듈의 기능은 패치
데코레이터를 사용하여 패치할 수 있으므로 제품/프로그램의 안정성 수준에 대한 더 나은 디버깅 및 제어가 가능합니다.
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedIn