unittest.TestCase.assertRaises(ValueError)를 context manager로 사용하고, 예외가 나야 하는 호출을 with 블록 안에 둡니다. 블록 안에서 ValueError가 발생하면 검증은 통과하고, 예외 없이 끝나면 테스트가 실패합니다.
다른 예외가 나오면 기대한 예외와 다르므로 테스트는 통과하지 않습니다. 테스트 대상 호출을 블록 밖에 두면 예외를 검사하지 못하므로 코드의 들여쓰기 범위를 확인해야 합니다.
예외 발생을 테스트의 기대 결과로 선언합니다
단위 테스트에서 예외가 발생했다고 해서 언제나 실패라고 볼 수는 없습니다. 함수 계약이 잘못된 입력을 거부해야 한다면 특정 예외가 발생하는 것이 기대 결과입니다. Python 3.12 unittest는 assertRaises를 제공하며, 이를 context manager로 쓰면 블록 안의 코드에서 지정한 예외가 발생했는지 확인할 수 있습니다. 내장 ValueError는 값은 적절한 자료형이지만 허용 범위나 의미에 맞지 않을 때 사용하는 예외입니다.
대상 호출을 with 블록 안에 둡니다
import unittest
def set_limit(limit):
if limit < 0:
raise ValueError("limit must be non-negative")
return limit
class LimitTests(unittest.TestCase):
def test_negative_limit(self):
with self.assertRaises(ValueError):
set_limit(-1)| 블록 안 동작 | 기대한 예외 | 검사 결과 |
|---|---|---|
| ValueError 발생 | ValueError | 통과 |
| 예외 없이 반환 | ValueError | 실패: 예외가 없음 |
| TypeError 발생 | ValueError | 오류(error): 기대와 다른 예외 |
첫 번째 경우에는 set_limit(-1)이 ValueError를 발생시키므로 기대한 동작으로 기록됩니다. 함수가 값을 반환하고 예외를 던지지 않으면 assertRaises는 조건이 충족되지 않았다고 보고 테스트를 실패시킵니다. 예외가 없는 경우는 assertion failure, TypeError처럼 기대와 다른 예외가 발생한 경우는 test error로 기록됩니다. 어느 쪽도 통과한 테스트가 아닙니다. assertRaises는 지정한 예외 클래스의 하위 클래스도 허용하므로, 테스트가 어떤 예외 계층을 받아들여도 되는지 필요에 따라 살펴보세요.
검증할 호출 범위를 짧고 분명하게 둡니다
- 입력 조건과 함수가 보장해야 할 예외 클래스를 정합니다.
with self.assertRaises(예외클래스):블록을 엽니다.- 예외가 나야 하는 함수 호출을 블록 안에 들여씁니다.
- 입력 하나에서 기대한 예외만 발생하는지 확인합니다.
- 정상 입력은 별도 테스트에서 반환값을 검사하고 다른 예외가 나오면 원인을 고칩니다.
함수를 블록 밖에서 호출하지 않습니다
다음 코드는 예외가 발생해도 검증이 되지 않습니다. set_limit(-1)을 with 문보다 먼저 실행하면 assertRaises 문맥이 그 호출을 검사하지 못하고, 테스트 실행기가 예외를 오류로 기록합니다. 반대로 with 블록 안에 실행할 코드가 없으면 예외가 나지 않아 실패합니다. 대상 호출뿐 아니라 예외를 발생시킬 준비 작업까지 무심코 블록 안에 두면, 준비 단계에서 발생한 ValueError가 검증을 통과하게 만들 수도 있습니다. 검사하려는 행위를 블록 안에 최소한으로 넣으세요.
# 잘못된 위치: 예외를 검사하는 블록 밖에서 호출
set_limit(-1)
# 올바른 위치: 호출을 with 블록 안에 배치
with self.assertRaises(ValueError):
set_limit(-1)예외 테스트는 실패 경로 하나만 다루지 말고 정상 값도 확인해야 함수가 항상 예외를 던지는 실수를 잡을 수 있습니다. 예를 들어 set_limit(0)이 0을 반환하는 테스트와 set_limit(-1)이 ValueError를 내는 테스트를 나눕니다. 예외 메시지가 계약의 일부일 때는 with self.assertRaises(ValueError) as caught:처럼 문맥 객체를 저장하고 caught.exception에서 예외 객체를 확인할 수 있습니다. 다만 메시지 전체를 고정하면 사소한 문구 변경에도 테스트가 깨질 수 있으므로 필요한 부분만 확인하세요.
정답을 가리고 확인해 보세요
이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.
assertRaises(ValueError) 블록 안의 함수 호출이 정상 반환하면 테스트 결과는 무엇인가요? TypeError를 던지면 ValueError 기대 검사는 통과하나요?
정답과 해설 확인
정상 반환은 기대 예외가 없어 실패(failure)입니다. TypeError는 기대와 다른 예외여서 오류(error)이며, 둘 다 통과하지 않습니다.context manager는 지정한 예외가 그 블록 안에서 발생하는지를 검사합니다. 테스트 대상 호출을 블록 안에 둬야 하며 ValueError와 상속 관계가 없는 TypeError는 해당 기대를 만족하지 않습니다.