TDD(Test-Driven Development)
테스트 크기
크기: 소비하는 자원과 수행할 수 있는 작업
- 작은 크기 테스트
- 단 하나의 프로세스에서 실행되어야 합니다
- sleep, I/O 연산 같은 블로킹 호출을 하면 안됩니다
- 외부 시스템과의 통신을 하면 안됩니다
- 개발하면서 수시로 호출합니다
- 중간 크기 테스트
- 여러 프로세스를 활용할 수 있습니다
- 블로킹 호출을 할 수 있습니다
- 외부 시스템과의 통신을 하면 안됩니다
- 큰 크기 테스트
- 여러 기기, 외부 시스템을 활용할 수 있습니다
- 릴리즈 때만 수행합니다
info
코드 커버리지는 작은 크기 테스트 에서만 측정되는 것이 좋습니다.
테스트 범위
범위: 테스트가 검증하고자 하는 코드의 양
info
5 줄의 코드를 포함하는 함수를 만들었을 때, 실행되는 코드의 양은 5 줄인지 몇 만 줄인지 알 수 없습니다. 하지만 검증해야할 코드는 5 줄이라고 보면 됩니다. 검증해야할 코드의 양이 범위를 나타내게 됩니다.
- 좁은 범위 테스트
- Unit Test
- 독립된 클래스나 메서드의 일부 로직을 검증합니다
- 중간 범위 테스트
- Integration Test
- 적은 수의 컴포넌트들 사이의 상호작용을 검증합니다
- 넓은 범위 테스트
- End-to-End Test
- 시스템 사이의 상호작용을 검증합니다
테스트 코드
- 리팩터링, 새 기능 추가, 버그 수정 시에는 기존 테스트를 변경할 일이 없어야 합니다
- 내부 구현(Private) 대신 공개 API(Public)를 테스트합니다
- 소수의 다른 클래스를 보조하는 함수나 클래스는 내부 구현으로 간주합니다
- 다수의 다른 클래스를 보조하는 함수나 클래스는 공개 API로 간주합니다
- 누구든 접근 가능한 함수나 클래스는 공개 API로 간주합니다
- 테스트 이름은 무엇을 테스트하는지 충분히 표현될 수 있도록 짓습니다
should
로 시작하는 이름을 쓸 수 있습니다- Ex)
shouldNotAllowWithdrawalsWhenBalanceIsEmpty
- 테스트를 행위별로 작성합니다
Given
/When
/Then
블록을 써서 표현합니다- 긴 블록은
And
로 구분하여 쪼갤 수 있습니다 - 불가피하게 여러 단계가 있는경우
When
/Then
이 반복 될 수 있습니다
- 언제 끝날지 모르는 결과를 기다릴 때는 sleep으로 적당히 큰 시간을 기다리기 보다 폴링과 타임아웃을 이용해서 테스트합니다
- 제어문을 최대한 사용하지 않습니다
- 테스트는 최대한 직설적으로 작성합니다(예상 결과를 변수를 조합해서 만들기보단 하드코딩 하기)
- 공유 값, 공유 셋업은 테스트를 간결하게 해주지만 테스트를 이해하기 위한 세부정보를 바로 알기 어렵게 만들 수 있으므로 주의해야합니다
테스트 대역(Test Double)
Stub, Mock
Stub
: 호출하면 미리 정한 값을 반환
Mock
: 호출을 어떻게 하는 지 검증
- 테스트 대상의 내부 구현을 노출해야하는 경우가 많아집니다
- Stub의 반환 값을 왜 그렇게 정했는지 설명이 필요할 수 있습니다
- 원하는 반환값이나 특정 오류를 일으키고 싶을 때 적합 할 수있습니다
- 호출이 어떻게 되는지 자체가 테스트 대상일 때 Mock을 사용할 수 있습니다
- 시스템 외부의 상태를 변화시키는 경우 Mock을 사용할 수 있습니다(Ex.
sendEmail()
)
Fake
Fake
: 실제 구현과 비슷하게 동작하도록 구현된 대역(Ex. InMemoryRepository
)
- 실제를 사용할 수 없을 때 최선일 수 있습니다
- 사용자가 적을 때, 유지 보수 비용이 생산성 보다 큽니다
- 가짜는 그 자체로 다시 테스트의 대상이 될 수 있습니다
- End-to-End 테스트 등에서 실제 구현으로 테스트할 때, 동일한 테스트를 가짜로도 수행하는 식으로 테스트할 수 있습니다
Classicist vs Mockist
Unit Test
- 실행 시간이 짧거나 애매한 경우 실제 구현 사용
- 실행 시간이 너무 긴 경우 테스트 대역 사용
- 결과에 랜덤성이 포함된 비결정적 테스트를 진행하는 경우 테스트 대역 사용
- 의존성 생성이 너무 복잡한 경우 테스트 대역 사용
Integration Test
End-to-End Test
Reference
- Titus Winters, Tom Manshreck, Hyrum Wright, Software Engineering at Google(번역본)