프레임워크의 존재 이유는 결국 이것이다 — 테스트가 실패했을 때 그 사실을 알려 주는 것. 그런데 21장의 run은 테스트 메서드가 예외를 던지면 그대로 같이 죽는다. 예외가 run을 뚫고 올라와 프로그램을 멈춘다. 그러면 실패를 세기는커녕 요약조차 못 낸다. 실패를 잡아 “실패 1건”으로 기록하고 다음으로 넘어가는 것 — 이게 이 장의 일이다.

실패는 잡아서 세는 것이지 터지는 게 아니다

해법은 try/except다. 테스트 메서드 호출을 try로 감싸고, 예외가 나면 except에서 result.testFailed()를 불러 실패 카운트를 올린다. 예외는 거기서 멈추고 프레임워크는 살아남는다. 이 구조가 있어야 21장에서 하드코딩으로 남겨 둔 0 failed를 진짜 카운트로 바꿀 수 있다 — 이제 실패를 만들어내는 테스트(testBrokenMethod)를 쓸 수 있으니, failureCount를 검증할 방법이 생겼다.

판단 기준: 실패는 프레임워크가 잡아 “데이터”로 기록해야 할 정상 흐름이지, 프레임워크를 멈추는 예외 상황이 아니다. 함정: try 범위를 너무 넓게 잡아 setUp까지 감싸면, 준비 단계의 오류와 테스트 본문의 실패가 뭉뚱그려진다 — 우선 테스트 본문의 실패부터 정확히 잡는다.

Refactoring Step 21장 끝 상태 — failed는 하드코딩, 예외는 run을 뚫는다
1/3
class TestResult:    def __init__(self):        self.runCount = 0    def testStarted(self):        self.runCount = self.runCount + 1    def summary(self):        return "%d run, 0 failed" % self.runCountclass TestCase:    def __init__(self, name):        self.name = name    def run(self):        result = TestResult()        result.testStarted()        self.setUp()        method = getattr(self, self.name)        method()        self.tearDown()        return result# failed는 상수 0. testBrokenMethod가 예외를 던지면 run을 뚫고 나가 프로그램이 죽는다.

두 번째 스텝에 testFailedResultFormatting에 해당하는 검증이 숨어 있다 — 실패를 한 건 만들고 summary()"1 run, 1 failed"라는 정확한 문자열을 내는지 확인하는 것. 21장의 하드코딩 0이 이제 errorCount라는 실제 값으로 대체되면서 그 중복이 사라졌다. 예외를 뭉뚱그려 잡는 except:는 거칠지만, 지금은 “실패를 잡아 세고 살아남는다”는 골격을 세우는 게 먼저다. 어떤 예외였는지 기록하는 정교함은 나중 몫이다.

이 장이 남긴 할 일 목록

  • 실패한 테스트 세기
  • 테스트 메서드가 실패해도 tearDown 부르기 — try 밖에 두어 항상 불린다
  • 여러 테스트 실행하기
  • setUp에서 난 오류도 잡아 기록하기

판단 기준: tearDowntry/except 에 두어, 테스트 본문이 실패해도 뒷정리는 항상 실행되게 했다 — 20장이 목록에 남겨둔 “실패해도 tearDown 부르기”가 이 배치로 함께 해결됐다.

다음장으로 23장