TDD는 테스트 주도 개발을 뜻하며 소프트웨어 개발 방법론 중 하나이다.
이는 개발 과정에서 작은 단위의 테스트 케이스를 먼저 작성하고 이를 통과시키는 것에 초점을 두는 방법론이다.
TDD의 핵심 목표는 코드의 품질을 높이고, 변경에 강한 코드를 작성하는 것이다.
TDD가 갖는 사이클은 크게 세 가지 단계로 나뉜다.

새로운 기능이나 수정사항을 구현하기 전, 이 기능이 무엇을 해야 하는지 정의하는 테스트를 작성한다.
과정
테스트 작성
새롭게 구현할 기능이나 수정할 부분에 대한 테스트를 작성한다.
기능이 기대한 대로 동작하는 지 확인하는 코드로, 개발자가 명확한 목표를 설정할 수 있게 한다.
테스트 실행
테스트를 실행하여 실패하는 것을 확인한다.
테스트 실패는, 기능이 구현되지 않았거나, 기존 코드가 수정되지 않았음을 의미한다.
이때의 실패는 예상된 실패이며, 이를 통해 테스트가 올바르게 작성되었는지를 확인할 수 있다.
RED 단계에서 작성한 테스트가 실패하며, 개발자는 실패 원인을 해결하기 위해 코드를 작성해야 함을 인식하게 된다.
실패한 테스트를 통과시키기 위해 필요한 최소한의 코드를 작성하는 단계이다.
테스트를 통과시키는 데 초점을 맞추며, 최적화나 구조 개선은 고려하지 않는다.
과정
코드 작성
테스트 통과를 위한 코드를 작성한다.
이때, 코드는 테스트를 통과하는 데 필요한 최소한의 기능만을 구현하며, 아직 최적의 코드일 필요는 없다.
테스트 실행 및 통과 확인
작성한 코드를 기반으로 테스트를 다시 실행한다.
이때 모든 테스트가 통과하면 GREEN 단계가 완료된다.
GREEN 단계에 작성한 코드를 개선하여 코드의 가독성과 성능, 유지보수성을 높이는 단계이다.
코드의 외부 동작을 변경하지 않으면서 내부 구조를 최적화하는 데 집중한다.
과정
코드 리팩토링
중복 코드 제거, 함수명 및 변수명 명확하게 수정, 모듈화 등의 리팩토링을 통해 코드를 정리한다.
이 과정에서 코드의 구조를 개선하여 유지보수가 용이하도록 만든다.
테스트 실행
리팩토링 후 테스트를 실행하여, 코드 수정으로 인해 기능에 문제가 생기지 않았는지 확인한다.
모든 테스트가 통과하면 리팩토링은 성공인 것이다.
막상 테스트 케이스를 작성하라고 하면 어떻게 작성해야 하는지 막막하다.
그래서 자주 사용되는 테스트 케이스 작성 방법론에 대해 알아보았다.
테스트 메소드를 세 가지 단계로 나누어 작성하는 방법이다.
Arrange
테스트에 필요한 모든 사전 조건을 설정한다.
여기에는 객체를 생성하거나, 필요한 데이터를 준비하는 작업이 포함된다.
Act
테스트할 동작을 실행한다. 보통 메소드를 호출하거나, 특정 작업을 수행하는 부분이다.
Assert
테스트의 결과가 예상대로인지 확인한다.
기대하는 결과와 실제 결과를 비교하여 테스트가 통과했는지 확인한다.
@SpringBootTest
class MyServiceTest {
@Autowired
private MyService myService;
@Test
void testCalculateTotal() {
// Arrange: 테스트에 필요한 데이터를 준비합니다.
int price = 100;
int quantity = 2;
// Act: 테스트할 메소드를 호출합니다.
int result = myService.calculateTotal(price, quantity);
// Assert: 예상 결과와 실제 결과를 비교합니다.
assertEquals(200, result);
}
}
BDD(Behaviour Driven Development, 행동 기반 개발)에서 주로 사용되는 방법론이다.
자연어에 더 가까운 방식으로 테스트를 작성하며, 비즈니스 요구사항에 좀 더 집중하여 테스트 케이스를 개발한다.
어떤 상황이 주어졌는가?
테스트의 초기 상태를 설정한다.
어떤 행동이 발생하였는가?
테스트할 동작을 실행한다.
그 행동의 결과로 이렇게 나와야 합니다.
예상 결과를 검증한다.
@SpringBootTest
class MyServiceTest {
@Autowired
private MyService myService;
@Test
void testCalculateTotal() {
// Given: 초기 상태를 설정합니다.
int price = 100;
int quantity = 2;
// When: 테스트할 동작을 실행합니다.
int result = myService.calculateTotal(price, quantity);
// Then: 결과를 검증합니다.
assertEquals(200, result);
}
}
두 패턴 모두 테스트의 로직을 명확하게 구분하여, 테스트가 어떤 과정을 거치는지 쉽게 이해할 수 있으며 가독성을 높인다.
3A 패턴은 좀 더 절차적이고 기술적인 표현을 사용한다.
하지만, GWT 패턴은 그와 다르게 좀 더 자연어에 가까운 표현을 사용하여 비즈니스 로직을 설명하는 데 유리하다.
코드의 품질 상승
테스트를 먼저 작성함으로써, 개발자는 코드가 올바르게 동작하는지 확인할 수 있다.
개발 과정의 오류를 줄임
테스트를 통해 코드의 동작을 검증함으로써, 오류를 사전에 발견하고 수정할 수 있다.
코드 유지보수를 용이하게 함
테스트 케이스는 코드의 동작을 문서화하는 역할을 한다.
이는 나중에 코드를 수정하거나 확장할 때 유용한 가이드가 된다.
개발자 생산성 향상
테스트를 통과하는 코드만 작성함으로써, 불필요한 코드를 작성하는 시간을 줄일 수 있다.
TDD는 개발자가 요구 사항에 집중하고, 필요한 기능만을 구현하도록 유도하기 때문이다.