TDD (Test-Driven Development)
TDD이란?
선 테스트 후 개발 방식의 프로그래밍 방법인 테스트 주도 개발.
테스트가 개발을 이끌어 나간다
반복 테스트를 이용한 소프트웨어 방법론
짧은 개발 사이클의 반복에 의존
테스트 코드를 먼저 작성해야 하는 이유
깔끔한 코드를 작성할 수 있다. (궁극적인 목표)
장기적으로 개발 비용을 절감할 수 있다.
개발이 끝나고 테스트 코드를 작성하는 것은 비용이 많이 든다.
단위 테스트와 통합 테스트
단위 테스트(Unit Test)란?
개념
하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트
모듈 : 애플리케이션에서 자동하는 하나의 기능 또는 메서드
기능이 올바르게 동작하는 지를 독립적으로 테스트하는 것
필요성
개발 및 테스팅에 대한 시간과 비용을 절감할 수 있음
새로운 기능 추가 및 수정 시에 수시로 빠르게 테스트 할 수 있음
리팩토링 시에 안정성을 확보할 수 있음
통합 테스트(Integration Test)란?
모듈 간의 호환성을 확인하는 테스트
모듈이 올바르게 연계되어 동작하는가
상호작용을 테스트하기 때문에 모든 컴포넌트들이 구동된 상태에서 진행됨
다른 컴포넌트와 연결하고 테스트
컴포넌트들이 많아질수록 비용이 상당히 커짐
추가) 좋은 테스트의 특징
좋은 테스트 코드는 FIRST라는 5가지 규칙을 따름(
CleanCode
참고) 빠르게 독립적으로 어느 환경에서든 실행이 가능하고 검증할 수 있어야 한다.
Fast
테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다.
Independent
각각의 테스트는 독립적이며 서로 의존해서는 안된다.
Repeatable
어느 환경에서도 반복 가능해야 한다(항상 같은 결과를 반환).
Self-Validating
테스트는 성공 또는 실패로 bool값을 결과를 내어 자체적으로 검증되어야 한다.
Timely
테스트는 적시에 즉, 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다.
+ 좋은 단위 테스트의 특징
1개의 테스트 함수에 대해
assert
를 최소화해야 한다.1개의 테스트 함수는 1가지 개념 만을 테스트해야 한다.
TDD 개발주기
🔴 Red 단계: 실패하는 테스트 코드를 먼저 작성한다.
구현해야 할 기능에 대한 테스트를 작성
해당 테스트를 구현한 코드가 아직 존재하지 않음
따라서 처음 작성한 테스트는 무조건 실패해야 함
🟢 Green 단계: 테스트 코드를 성공시키기 위한 실제 코드를 작성한다.
추가된 테스트를 반영하여 구현 코드를 작성할 때는 최소한의 코드 변경만 존재해야 함
추가된 테스트에 대해서만 메인 코드가 작성되어야 부작용이 적음
🔵 Blue 단계: 중복 코드 제거, 일반화 등의 리팩토링을 수행한다.
설계를 개선하고 중복 코드를 제거
리팩토링
중요한 것은 실패하는 테스트 코드를 작성할 때까지 실제 코드를 작성하지 않는 것과 실패하는 테스트를 통과할 정도의 최소 실제 코드를 작성해야하는 것이다. 이를 통해 실제 코드에 대해 기대되는 바를 보다 명확하게 정의 함으로써 불필요한 설계를 피할 수 있고, 정확한 요구사항에 집중할 수 있다.
TDD와 일반 개발 과정과의 차이점
➡️ 일반 개발 방식
요구사항 분석 ➡ 설계 ➡ 개발 ➡ 테스트 ➡ 배포
이러한 방식은 소트프웨어 개발을 느리게 하는 잠재적 위험이 존재
소비자의 요구사항의 불명확성
따라서 처음부터 완벽한 설계가 불가능
자체 버그 검출 능력 또는 소스코드 품질 저하
자체 테스트 비용이 증가할 수 있음
이러한 코드들은 재사용이 어렵고 관리가 어려워서 유지보수를 어렵게 만듦
모든 부분을 테스트해야하기 떄문에 전체적인 버그를 검출하기 어려워짐
이로 인해 버그가 어디서 생길지 몰라 잘못된 코드도 방치하는 일이 생김
🔄 TDD 개발방식
단위 테스트 작성 → 단위 테스트 실행 → 운영 코드 작성 → 단위 테스트 실행 → 설계 개선(리팩토링) → 단위 테스트 실행
테스트 케이스 먼저 작성(일반적인 개발 방식과 가장 큰 차이점)
기능 코드를 구현하지 않았으므로 테스트 결과는 실패한다.
테스트 케이스를 통과하는 코드 작성
테스트 코드를 만족시킬 수 있는 기능을 구현한다.
작성한 코드 리팩토링
성능, 재사용성, 가독성 향상
TDD의 효과(장점)
높은 코드 안전성(객체 지향적인 코드)
의존성이 낮은 모듈 -> 모듈을 추가하거나 제거해도 전체 구조에 영향을 끼치지 않게 된다.
재설계 시간의 단축
다양한 예외사항에 대해 생각 -> 전반적인 설계가 변경되는 일 방지
디버깅 시간 단축
단위 테스트를 통해 특정 버그를 손 쉽게 찾아낼 수 있다.
테스트 문서의 대체
정확한 테스트 근거를 산출해서 테스트 문서를 대체할 수 있다.
추가 구현에 용이함
자동화된 유닛 테스팅을 전제하므로 테스트 시간을 획기적으로 단축시킬 수 있음
TDD의 단점
생산성 저하(가장 큰 단점)
프로덕션과 테스트 코드 2개를 작성해야함
기한이 짧으면 TDD를 적용하기에 비효율적일 수 있음(ex. SI 프로젝트)
구조에 얽매임
반드시 툴(단위 테스트 프레임워크)을 써서 개발해야 한다고 생각함
규칙에 얽매이는 것은 애자일 방식이 아니며, 이 때문에 똑같은 테스트를 반복함
+ TDD의 대표적인 Tool 'JUnit'
현재 전 세계적으로 가장 널리 사용되는
Java 단위 테스트 프레임워크
JUnit을 시작으로 CUnit(C언어), CPPUnit(C++), PyUnit(Python) 등 xUnit 프레임워크가 탄생함
given-when-then
패턴1개의 단위 테스트를 3가지 단계로 나누어 처리하는 패턴으로, 요즘 단위 테스트에서 많이 작성함
given(준비): 어떠한 데이터가 준비되었을 때
when(실행): 어떠한 함수를 실행하면
then(검증): 어떠한 결과가 나와야 한다.
+ Spring의 단위 테스트 'Mockito'
개발자가 동작을 직접적으로 제어할 수 있는 가짜 객체를 지원하는 테스트 프레임워크
Spring 어플리케이션은 여러 객체들 간의 의존성이 생기는데 이러한 의존성을
Mockito
를 이용하여 단절 시킴으로 단위 테스트를 쉽게 작성하는 것을 도움JUnit과 같이 자주 쓰임.
참고
https://hanamon.kr/tdd%EB%9E%80-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C/
https://inpa.tistory.com/entry/QA-%F0%9F%93%9A-TDD-%EB%B0%A9%EB%B2%95%EB%A1%A0-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C
Last updated