setUp이 상을 차렸으면 누군가는 상을 치워야 한다. 열었던 연결을 닫고, 심었던 데이터를 지운다. 그 자리가 tearDown이다. 그런데 이 장의 진짜 알맹이는 tearDown 자체가 아니라, 호출 순서를 어떻게 검증하느냐다.
플래그 여러 개는 순서를 증언하지 못한다
19장까지의 방식대로라면 wasTornDown 플래그를 하나 더 만들면 된다. 하지만 플래그가 늘어날수록 정작 알고 싶은 것 — “setUp → testMethod → tearDown 순서로 불렸는가” — 은 확인하기 어려워진다. 플래그는 “불렸다/안 불렸다”만 말할 뿐 언제 불렸는지 순서를 증언하지 못한다.
벡의 해법이 우아하다. 플래그를 다 버리고 로그 문자열 하나를 둔다. 각 훅이 불릴 때마다 자기 이름을 문자열 뒤에 이어 붙인다. 실행이 끝나면 log는 "setUp testMethod tearDown "이 되어 있다 — 무엇이 몇 번 어떤 순서로 불렸는지가 문자열 하나에 다 담긴다.
판단 기준: 여러 개의 불리언 상태로 흩어져 검증할 것을 하나의 관찰 가능한 값으로 모을 수 있다면 모은다 — 검증이 한 줄로 단순해진다. 함정: 순서가 중요한 협력을 불리언 플래그들로 검증하려 들면, 통과해도 순서가 맞는지 알 수 없는 반쪽짜리 테스트가 된다.
class TestCase: def __init__(self, name): self.name = name def setUp(self): pass def run(self): self.setUp() method = getattr(self, self.name) method()class WasRun(TestCase): def setUp(self): self.wasRun = None self.wasSetUp = 1 def testMethod(self): self.wasRun = 1test = WasRun("testMethod")test.run()print(test.wasSetUp)
로그 문자열은 단순한 편의가 아니다. 테스트 대상(WasRun)이 자기가 받은 호출을 log에 남기고, 테스트는 그 log만 읽어 협력이 약속대로 일어났는지 판정한다 — 나중에 벡이 Self Shunt 패턴으로 정식화할 아이디어의 원형이다. 별도의 목(mock) 라이브러리 없이, 관찰 대상이 곧 기록자가 된다.
이 장이 남긴 할 일 목록
나중에 tearDown 부르기- 테스트 메서드가 실패해도 tearDown 부르기 — 예외가 나면 tearDown에 못 닿는다
- 여러 테스트 실행하기
- 수집된 결과 출력하기 (“5개 실행, 2개 실패”)
판단 기준: tearDown을 run 끝에 그냥 붙였다. 하지만 테스트 메서드가 예외로 죽으면 tearDown에 도달하지 못한다는 결함을 목록에 적어 둔다 — 다음 장의 실패 처리와 함께 풀 문제다.
다음장으로 21장