✏️ TDD - Test Driven Development
Test code 를 먼저 만들고, 실제 프로덕션 code 를 나중에 만드는 개발 방법
설계 --> 개발 --> Test
<- 설계 수정 --
설계 ------> Test --> 개발
<- 설계 수정 --
📍 TDD 의 개발 사이클
- 실패하는 Test 를 구현한다.
- Test 가 성공하도록 프로덕션 code 를 구현하낟.
- 프로덕션 code 와 test code 를 리팩토링 한다.
- 1번부터 반복한다.
📍 TDD 의 장점
- 변화에 대한 두려움을 줄여준다.
- 디버깅 시간을 줄여준다.
- 동작하는 문서 역할을 한다.
- 자언스럽게 Test 커버리지가 높아진다.
- Test 를 까먹거나 뒤로 미루다 하지 안게되는 문제를 방지해준다.
- 오버 엔지니어링 방지
- 불필요한 코드 없이 정말 지금 딱 필요한 만큼만 구현할 수 있다.
📍 TDD 의 단점
- 높은 응집도를 유도하지 않는다.
- 단일 책임 원칙과 인터페이스 분리 원칙 위배에 어떠한 신호도 주지 않는다.
- 인터페이스 일관성을 도출하지 않는다.
- 리팩토링 단계는 좋은 구조를 안내하거나 좋은 구조를 갖도록 강제하지 않는다.
⚠️ TDD 에 너무 많은 의존을 하게되면 Test 하기에만 좋은 code 가 되어 버린다.
📍 TDD 에 실패하는 이유
- code 가 이루고자 하는 가치나 기능을 Test 하기보다는 그 기능을 어떻게 구현하고 있는지를 Test 한다.
- 결국 Test case 들이 구현체와 결합도가 높아진다.
- 구현체들을 리팩토링하면 결합되어있는 Test case 들이 모두 깨져버린다.
📍 해결방법
- 내부의 구현체를 Test 하는 것이 아닌 interface 자체를 test 한다.
📍 Test 범위에 따른 분류
- 단위 Test
- Method 레벨의 가장 작은 단위의 test
- 단위 테스트는 목적 코드의 완전성을 입증 해주기 때문에,
Test code 그 자체만으로 주요한 가치가 있다.
- 통합 Test
- 여러 작업 단위가 연계된 워크플로우를 Test 하기 위한 수단
- 객체 간, 서비스 간, 시스템 간
- 기능 Test
- 공개된 API 의 가장 바깥쪽에 해당하는 코드 검사
- Controller 호출, Security, http
- 부하 Test
- 주어진 단위 시간 동안 어플리케이션이 얼마나 많은 요청을 처리할 수 있는지 검사
- 인수 Test
- 고객 또는 대리인이 정의되어진 모든 목적에 부합하는지 확인해보고자 하는 검사
📍 단위 Test 의 목적
- 각 단위가 정확하게 동작하는지 검사하기 때문에 문제가 발생할경우 어느 부분이 잘못되었는지 재빨리 확인할 수 있게 된다.
- 문제점이 발견되면 빠르게 코드를 수정할 수 있고,
수정된 코드가 잘 작동하는지 쉽게 알 수 있어 변경을 자주 할 수 있다.
- 단위 Test code 의 로직이 복잡하면 프로덕션 코드에 불필요한 로직이 많다는 뜻이고,
이는 리팩토링이 필요하다는 뜻으로 이어진다.
- 결국 코드 품질의 향상으로 이어지게 된다.
- 예외 상황, 용도, 의존 관계를 한눈에 파악할 수 있고,
단위 Test 는 배포되는 코드와 일치하므로 항상 최신상태로 유지된다.
- 코드의 문서화
✏️ 좋은 Test 의 법칙 - F.I.R.S.T
- F - Fast (빠르게)
- Test 를 자주 하기 위해선 검증이 빨라야 한다.
- I - Independent (독립적으로)
- 각 Test 는 서로 의존하지 않고 독립되어야 한다.
- 문제의 근본적인 원인과 위치를 파악할 수 있음
- R - Repeatable (반복 가능하게)
- S - Self - Validating (자가 검증하는)
- Test 는 성공과 실패를 명확하게 개발자에게 알려주어야 한다.
- T - Timely **(적시에)
- Test 를 하기 까다로운 상황이 발생되지 않게 제 때 제 때 Test 를 해주어야 한다.
- 만약 Test 를 하기 어려운 코드일 경우 코드를 수정해야 하기 때문