앞 장이 “언제 실패하는 테스트를 쓰는가”였다면, 이 장은 “테스트를 어떻게 쓰는가”의 실전 기술이다. 협력하는 객체가 아직 없거나, 무거운 자원(DB·네트워크)에 의존하거나, 검증 지점이 여러 개일 때 쓰는 도구들이 모여 있다.
큰 테스트를 쪼갠다
자식 테스트. 지금 통과시키려는 테스트가 너무 커서 한 번에 초록으로 못 가면, 그 일부를 표현하는 더 작은 테스트를 따로 만들어 먼저 통과시킨다. 작은 것이 초록이 되면 큰 것으로 돌아온다. 걸음이 너무 컸다는 신호에 대한 응급 처치다.
판단 기준: 빨강이 여러 원인으로 동시에 떠 있으면 자식 테스트로 하나씩 분리할 때다. 함정: 자식 테스트를 만들고 원래의 큰 테스트를 지워 버리면, 통합된 동작을 검증하는 지점이 사라진다 — 큰 테스트는 남겨 둔다.
협력 객체를 대신 세운다
모의 객체(Mock). 준비 비용이 크거나(데이터베이스) 결과가 매번 다른(현재 시각, 난수) 협력 객체 대신, 정해진 답만 돌려주는 가짜를 세운다. 테스트는 빨라지고 결과는 결정적이 된다. 모의 객체는 협력자에 대한 우리의 “기대”를 코드로 명시하는 효과도 있다.
class MockDatabase:
def balance(self, account):
return 100 # 언제나 같은 값 — 결정적이고 빠르다
def test_withdraw():
account = Account(MockDatabase())
assert account.can_withdraw(50) is True셀프 션트(Self Shunt). 별도의 모의 클래스를 만드는 대신, 테스트 케이스 자신을 협력 객체로 넘긴다. 테스트가 인터페이스를 구현하고, 자기 자신을 대상 객체에 주입한 뒤, 콜백으로 넘어온 값을 필드에 담아 검증한다. 20장에서 진행 표시줄을 검증할 때 쓴 바로 그 기법이다. 가짜 클래스 하나를 아낄 수 있다.
class NotifierTest(unittest.TestCase):
def log(self, message): # 테스트가 리스너를 직접 구현
self.received = message
def test_notifies(self):
Notifier(self).fire("hi") # 자기 자신을 주입
assert self.received == "hi"판단 기준: 협력 객체의 인터페이스가 메서드 한둘로 작으면 셀프 션트가 가볍다. 커지면 별도 모의 클래스가 깔끔하다. 함정: 모의 객체가 실제 객체와 동작이 어긋나면 테스트는 초록인데 운영은 깨진다 — 모의의 계약을 실제와 맞춰 두거나 학습 테스트(26장)로 실제 동작을 검증한다.
검증을 문자열로 모은다
로그 문자열. 콜백이 “언제, 몇 번, 어떤 순서로” 불렸는지를 검증하고 싶을 때, 호출될 때마다 문자열에 기록을 덧붙이고 마지막에 그 문자열 전체를 한 번에 단언한다. 순서까지 검증되는 게 장점이다. 이것도 20장에서 템플릿 메서드의 훅 호출 순서를 확인할 때 쓴 방법이다.
def test_template_order(self):
self.log = ""
self.run_template() # setUp / test / tearDown 훅이 log에 append
assert self.log == "setUp test tearDown"판단 기준: 검증 대상이 “값”이 아니라 “호출 순서·횟수”라면 로그 문자열이 가장 직관적이다. 함정: 문자열 하나에 너무 많은 걸 몰아 담으면 실패 메시지가 어디가 틀렸는지 못 짚어 준다 — 검증 단위를 적당히 나눈다.
최소한의 가짜와 일부러 깬 테스트
크래시 테스트 더미. 정상 경로가 아니라 오류 경로(예외 처리)를 검증할 때, 호출되면 그냥 예외를 던지는 최소한의 가짜를 세운다. 디스크 꽉 참, 네트워크 끊김처럼 실제로 재현하기 어려운 실패를 손쉽게 흉내 낸다.
class FullDiskFile:
def write(self, data):
raise IOError("disk full") # 재현 어려운 실패를 강제 발생
def test_handles_full_disk():
with pytest.raises(IOError):
Saver(FullDiskFile()).save("data")깨진 테스트. 혼자 작업하다 세션을 중단할 때, 일부러 실패하는 테스트 하나를 남겨 둔다. 다음에 앉으면 빨간 막대가 “여기서 멈췄다”고 정확히 알려 준다. 완성된 초록 상태로 끝내면 오히려 어디서부터 시작할지 헤맨다.
판단 기준: 오류 경로 검증엔 완전한 가짜가 필요 없다 — 예외만 던지는 더미로 충분하다. 함정: 깨진 테스트를 팀 공유 브랜치에 남기면 남의 빌드를 깬다 — 이 패턴은 혼자 작업하는 로컬에서만 쓴다.
다음장으로 28장