TDD란?
- 반복 테스트를 이용한 소프트웨어 방법론
- 작은 단위의 테스트 케이스를 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 구현
- 짧은 개발 주기의 반복에 의존하는 개발 프로세스
- 애자일 방법론 중 하나인 eXtream Programming(XP)의 ‘Test-First’ 개념에 기반
- 모든 직무에서 TDD를 적용 가능
eXtream Programming(XP)
미래에 대한 예측을 최대한 하지 않고 지속적으로 프로토타입을 완성하는 애자일 기방법론 중 하나
추가 요구사항이 생기더라도 실시간으로 반영 가능
단위 테스트(unit Test)
한 단위(일반적으로 class)만을 테스트 하는 것
애자일 방법론
신속한 반복 작업을 통해 실제 작동 가능한 소프트웨어를 개발하여 지속적으로 제공하기 위한 소프트웨어 개발 방식
일반 개발 방식과 TDD 개발 방식의 비교
일반 개발 방식
- 개발 주기 : 요구사항 분석 → 설계 → 개발 → 테스트 → 배포
- 고객의 요구사항 또는 디자인의 오류 등 많은 외부 또는 내부 조건에 의해 재설계하여 점진적으로 완성도를 높임
문제점
- 어느 프로젝트든 초기 설계가 완벽하지 않기에 소프트웨어 개발을 느리게 하는 잠재적 위험이 있음
- 재설계로 인해 개발자는 코드를 삽입, 수정, 삭제하는 과정에서 불필요한 코드가 남거나 중복처리 될 수 있음
- 이러한 코드들은 재사용이 어렵고 관리가 어려워서 유지보수가 까다로워지며 테이스 비용이 증가
TDD 개발 방식
- 테스트케이스를 먼저 작성한 이후에 실제 코드를 개발하는 리팩토링 절차 진행
- 디자인(설계) 단계에서 프로그래밍 목적을 반드시 정의하고, 무엇을 테스트해야 할지 미리 정의 (테스트 케이스 작성)
- 작은 단위부터 시작하여 점진적으로 개발
- TDD의 목표 : Clean Code
- 테스트 코드를 작성하는 도중에 발생하는 예외 사항(버그, 수정사항)들은 테스트 케이스에 추가, 설계 개선
- 테스트가 통과된 코드만을 코드 작성 단계에서 실제 코드로 작성
- 반복적인 단계가 진행되면서 자연스럽게 코드의 버그 감소, 소스코드 간결화, 재설계 시간이 절감
- TDD를 활용하면, 시작 단계에서 테스트케이스를 설계하기 위한 초기 비용 증가
- 그러나 유지 보수 비용이 크거나 안정성이 중요한 프로젝트의 경우 TDD 방식 개발이 효율적
TDD 개발 프로세스
- 하나의 작은 단위의 테스트 코드를 작성
- 테스트
- 테스트가 통과될 때까지 테스트 코드를 수정
- 테스트가 통과된 테스트 코드 리펙토링
- 리펙토링한 코드 테스트
- 리펙토링한 코드가 통과 될때까지 코드 수정
- 테스트가 통과되면 테스트 케이스에 있는 다음 테스트 코드 작성
TDD 개발 주기
TDD의 개발 프로세스를 따라가다 보면 발생하는 반복적인 패턴에 대해 시간별 주기
나노 주기 (TDD의 3가지 규칙)
코드의 행 단위의 개발 및 테스트
초 단위의 반복적인 테스트 주기가 발생
- 먼저 실패하는 테스트 코드를 작성
- 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 테스트 코드를 작성
- 현재 실패하는 테스트 코드가 통과된 코드만 실제 코드에 작성
RGR 주기
단위 테스트마다 발생
분 단위 발생
Red
실패하는 테스트 코드를 먼저 작성
Green
테스트 코드를 성공시키기 위한 실제 코드를 작성
Refactor
통과된 테스트 코드를 리팩토링
유의점
- 실패하는 테스트 코드를 작성할 때까지 실제 코드를 작성하지 않음
- 실패하는 테스트를 통과할 정도의 최소 실제 코드를 작성
- -> 실제 코드에 대해 기대되는 바를 보다 명확하게 정의 함으로써 불필요한 설계 감소, 정확한 요구 사항에 집중
- Red 단계에서 Green로 진행되는 과정에서 복붙, 설계를 무시한 개발 가능
- -> 발생하는 중복된 코드, 올바르지 못한 구조 등은 Refactor 단계에서 해결
단위 테스트의 FIRST 규칙
단위 테스트 작성 기준
TDD의 주기들은 Clean code that works 지향하기에 리펙토링 과정이 필수적
리펙토링은 RGR 주기에서 단위 테스트 단위로 이루어지기에 단위 테스트와 TDD는 밀접한 관계를 맺음
Fast - 단위 테스트는 빨라야 한다.
- 기준 : 밀리 초(ms)
- 실행 시간이 0.5 초 또는 0.25 초가 걸리는 테스트는 빠른 테스트가 아님
Independent - 단위 테스트에 사용된 데이터들은 서로 의존하면 안 된다.
- 테스트에 필요한 데이터는 테스트 내부에서 독립적으로 사용 되어야 함
- 데이터의 존재 여부를 찾는 테스트가 있는 경우 해당 데이터는 테스트 내부에서 생성, 후의 테스트에 영향을 미치지 않도록 제거
Repeatable - 단위 테스트는 어느 환경에서든 반복적으로 테스트를 실행할 수 있어야 한다.
- 환경 : 네트워크 나 데이터베이스에 의존하지 않는 환경
- 인터넷이 되든 안 되든 데이터베이스에 접속하든 안 하든 언제 어디서나 테스트 가능해야함
- 환경에 의존하지 않는 테스트가 실패할 수 있는 유일한 이유는 테스트할 클래스 또는 메소드가 제대로 작동하지 않은 경우
Selef-Validating - 단위 테스트는 자체 검증이 되어야 한다.
- 테스트의 검증은 수작업이 아닌 자동화
- 테스트가 실행될 때마다 메서드 출력이 올바른지를 확인하는 것은 개발자가 결정 불가능
- 따라서 자바 환경에서는 테스트에 대한 검증을 지원하는 JUnit을 사용하여 테스트의 통과 여부를 결정
Timely – 단위 테스트는 실제 코드를 작성하기 전에 작성해야된다.
대표적인 툴
JUnit
Java 단위 테스트 프레임워크
JUnit을 시작으로 CUnit(C언어), CPPUnit(C++), PyUnit(Python) 등 xUnit 프레임워크가 탄생
JUnit 환경 구축
https://nesoy.github.io/articles/2017-02/JUnit
xUnit
CUnit(C언어), CPPUnit(C++), PyUnit(Python) 등 각각의 언어로 단위 테스트를 하기 위한 프레임워크
TDD 방식의 장점
짧은 개발 주기
고객의 요구사항 빠르게 수용 가능
즉각적인 피드백이 가능하고 진행 상황 파악이 쉬움
시스템 결함 방지
작업과 동시에 테스트를 진행하면서 실시간으로 오류 파악이 가능
보다 튼튼한 객체 지향적인 코드 생산
코드의 재사용 보장을 명시하므로 TDD를 통한 소프트웨어 개발 시 기능별 모듈화 가능
종속성과 의존성이 낮은 모듈로 조합된 소프트웨어 개발로 필요에 따라 모듈을 추가하거나 제거해도 소프트웨어 전체 구조에 영향을 미치치 않음
재설계 시간의 단축
테스트 코드를 먼저 작성하기 때문에 필요한 부분을 명확히 정의하고 시작 가능
테스트 시나리오를 작성하면서 다양한 예외사항에 대비
개발 진행 중 소프트웨어의 전반적인 설계가 변경되는 일을 방지
디버깅 시간의 단축
자동화 된 유닛 테스팅을 전제하여 특정 버그를 손 쉽게 찾아낼 수 있음
일반적으로 개발한다면 사용자의 데이터가 잘못 나올 경우 DB, 비즈니스 레이어, UI 등 실제 모든 레이어들을 전부 디버깅 해야함
테스트 문서의 대체 가능
주로 SI 프로젝트 진행 과정에서는 어떤 요소들이 테스트 되었는지 테스트 정의서 제작함
TDD를 통해 테스팅을 자동화 시킴과 동시에 보다 정확한 테스트 근거를 산출 가능
추가 구현의 용의함
자동화된 유닛 테스팅으로 테스트 기간 단축
TDD 방식의 단점
생산성 저하, 생산비용 증가
기존 개발 프로세스에 테스트케이스가 추가되면서 개발속도가 더 느려지고 생산비용도 증가
SI 프로젝트에서는 소프트웨어의 품질보다는 납기일 준수가 훨씬 중요하기 때문에 TDD 방식을 잘 사용하지 않음
테스트의 방향성, 프로젝트 성격에 따른 테스트 프레임워크 선택 등 고려 사항 증가
TDD 예제
생년월일(input)을 입력받으면 현재 나이(output)를 출력하는 프로그램
- 간단한 목표 설정 (태어난 해와 올해의 연도 입력)
- - 2015, 2018 -> (만)3살
- 만들기 전 제작 후 무엇을 테스트할지를 설계
- -> 2015, 2018를 입력하면 2가 나오는 테스트 프로그램(장차 만들 프로그램을 테스트 할 코드)
- 그 테스트를 통과할 프로그램(1.에 해당하는 코드) 제작
- -> 올해의 연도 - 태어난 해 / 2018 - 2015
- 테스트 프로그램으로 이 프로그램(3.에 해당하는 코드)을 실행
- 통과 시 새로운 테스트를 추가
- 생월을 추가했을 때 계산하는 프로그램 제작
- 위 과정 반복 수행
TDD를 잘하는 방법
본인의 작업 방식 지속적 업그레이드
중복적으로 하는 노력들을 자동화 할 수 있도록 고민
ex) 게임을 개발하면서 stage 3를 테스트 할 때, 항상 stage 1, stage 2를 클리어한 뒤 테스트 진행
—> 테스트 비용이 증가한다.
어떻게 하면 비용을 낮출 수 있을까?
—> 바로 stage 3으로 갈 수 있도록 만든다.
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://gyoogle.dev/blog/computer-science/software-engineering/TDD.html