TDD (Test Driven Development)
: 테스트 코드를 먼저 작성하고, 그 테스트를 통과하는 실제 코드를 작성하는 개발 방법론
- 짧은 개발 주기의 반복에 의존하는 개발 프로세스로, 애자일 방법론 중 하나인 eXtream Programming(XP)의 'Test-First' 개념에 기반을 둔 단순한 설계를 중요시한다.
- 소프트웨어의 품질, 성능, 신뢰성을 평가하는 과정
- 프로그램 실행을 통해 오류를 발견하고 수정하는 활동
- 예상 결과와 실제 결과를 비교 및 검증
eXtream Programming(XP)
미래에 대한 예측을 최대한 하지 않고, 지속적으로 프로토타입을 완성하는 애자일 방법론 중 하나이다.
이 방법론은 추가 요구사항이 생기더라도, 실시간으로 반영할 수 있다.
TDD의 기본 원칙
- 아래 과정은 Red-Green-Refactor 사이클로 반복되며, 이를 통해 점진적으로 품질 높은 코드를 만들어나간다.
- 테스트를 먼저 작성한다.
- 구현하려는 기능의 목표를 명확히 하기 위해 먼저 테스트 코드를 작성한다.
- 테스트는 실패 상태로 시작해야 한다.
- 테스트를 통과하는 최소한의 코드를 작성한다.
- 테스트를 통과하는 데 필요한 최소한의 코드만 작성하며, 불필요한 기능은 포함하지 않는다.
- 단순히 테스트 성공을 목표로 코드를 작성한다.
- 리팩토링을 한다.
- 테스트를 통과한 후 코드의 가독성과 효율성을 높이기 위해 리팩토링한다.
- 중복 코드를 제거하고 구조를 개선하며, 테스트가 성공하는 상태를 유지한다.
TDD 개발주기
- TDD 주기는 테스트, 코드 작성, 리팩토링의 반복으로, 코드 품질을 점진적으로 향상시킨다.
- 이 과정을 통해 불필요한 설계를 피하고, 정확한 요구 사항에 집중할 수 있다.
1. Red 단계
- 실패하는 테스트 코드를 작성한다.
- 구현하려는 기능에 대한 테스트를 먼저 작성하며, 테스트는 실패 상태로 시작한다.
- 중요한 점은 실제 코드를 작성하기 전에 테스트 코드를 먼저 작성하는 것이다.
2. Green 단계
- 테스트를 통과하는 최소한의 실제 코드를 작성한다.
- 실패한 테스트를 통과할 수 있도록 최소한의 코드만 작성한다.
- 이 단계의 목표는 테스트를 성공시키는 것이므로, 품질 고려는 최소화한다.
3. Refactor(Yellow) 단계
- 리팩토링을 수행한다.
- 중복 코드를 제거하고, 코드를 일반화하여 가독성과 효율성을 개선한다.
- 중요한 점은 리팩토링을 통해 테스트가 성공하는 상태를 유지하는 것이다.
일반 개발 방식 vs TDD 개발 방식
일반 개발 방식
- 일반적인 개발 방식은 요구사항 분석 → 설계 → 개발 → 테스트 → 배포 단계를 따르는 주기를 갖는다.
위험 요소
- 소비자의 요구사항이 명확하지 않을 수 있다.
- 초기 단계에서 완벽한 설계를 만드는 것은 어려움이 있다.
- 코드 품질 저하 가능성
- 재설계 과정에서 불필요하거나 중복된 코드가 남을 가능성이 커진다.
- 결과적으로 코드 재사용이 어려워지고 관리 및 유지보수가 복잡해진다.
- 버그 검출 능력 저하
- 프로젝트 규모가 커질수록, 작은 수정에도 모든 기능을 테스트해야 하므로 전체적인 버그를 발견하기 어려워진다.
- 테스트 비용 증가
- 모든 기능을 다시 테스트해야 하기 때문에 자체 테스트 비용이 크게 증가한다.
위험 요소가 생기는 원인
- 초기 설계가 완벽할 수 없고, 프로젝트 진행 중 고객 요구사항 변경, 디자인 오류 등 여러 조건의 문제가 발생하기 때문이다.
- 이 과정에서 재설계가 필요하고, 코드 삽입, 수정, 삭제가 반복되면서 코드의 품질이 저하되고 관리가 어려워진다.
결론
- 코드 재사용이 어렵고, 관리가 복잡해져 유지보수가 점점 더 어려워진다.
- 작은 수정에도 전체 테스트가 필요하며, 이로 인해 버그 검출 능력이 저하되고 테스트 비용이 증가한다.
TDD 개발 방식
- TDD는 테스트 코드를 먼저 작성한 후 실제 코드를 작성하는 방식이다.
- 반면, 일반적인 개발 방식은 보통 설계 후에 코드 작성과 테스트가 진행된다.
개발 과정
- 설계 단계에서 프로그래밍 목적과 테스트할 내용을 미리 정의해야 한다.
- 테스트 코드를 작성하고, 코드 작성 중 발생하는 버그나 수정 사항은 테스트 케이스에 추가하고 설계를 개선한다.
- 이후 테스트가 통과된 코드만 실제 코드 개발 단계에서 작성한다.
장점
- 반복적인 단계를 통해 자연스럽게 코드의 버그가 줄어들고, 소스코드는 간결해집니다.
- 테스트 케이스 작성 과정에서 설계가 자연스럽게 개선되며, 이로 인해 재설계 시간이 절감됩니다.
TDD의 장단점
장점 | 단점 |
|
|
Test Tools
1. Jest
: JavaScript용 테스트 프레임워크
- 주로 React 애플리케이션에서 사용되며, 단위 테스트와 통합 테스트를 효율적으로 처리할 수 있다.
- 테스트 러너, 어설션 라이브러리, 모킹(mocking) 등을 모두 제공하여, 테스트를 손쉽게 작성하고 실행할 수 있도록 돕는다.
장점
- 별도의 설정 없이 바로 테스트를 작성하고 실행 가능
- React 컴포넌트와 함께 사용할 때 직관적이고 효율적인 테스트 가능
- 스냅샷 테스트와 모킹 기능 제공
- 빠른 테스트 실행을 위한 병렬 처리 기능
특징
- 자동화된 테스트 실행: 테스트가 자동으로 실행되며, 실패한 테스트를 쉽게 확인할 수 있다.
- 스냅샷 테스트: UI 컴포넌트의 스냅샷을 저장하여, 이후 변경 사항을 확인할 수 있다.
- 빠른 테스트 실행: 병렬 실행을 통해 테스트 결과를 빠르게 확인할 수 있다.
- 모킹 기능: 외부 API 호출이나 의존성 모킹을 통해, 테스트 환경을 통제할 수 있다.
- Zero Configuration: 기본 설정만으로 바로 사용 가능하며, 별도의 설정 없이 테스트를 실행할 수 있다.
// 테스트할 함수
function add(a, b) {
return a + b;
}
// Jest를 사용한 단위 테스트
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
2. React Testing Library (RTL)
: React 애플리케이션의 UI 컴포넌트를 테스트하기 위한 라이브러리
- RTL은 "UI가 어떻게 동작하는지"에 초점을 맞추며, 실제 사용자가 상호작용하는 방식대로 테스트를 작성할 수 있도록 돕는다.
- 내부 구현보다는 사용자 경험 중심으로 테스트를 진행합니다.
장점
- 컴포넌트의 동작을 실제 사용자처럼 테스트
- UI가 실제로 어떻게 동작하는지 테스트
- Jest와 통합하여 더욱 강력한 테스트 환경 구성
특징
- 사용자 경험 중심: 실제 사용자가 컴포넌트를 어떻게 사용하고 상호작용하는지를 테스트한다.
- DOM 접근: 렌더링된 컴포넌트의 DOM을 직접 조작하여 테스트를 진행한다.
- 추천 테스트 접근: 컴포넌트 내부 구현이 아니라 UI의 동작을 테스트한다.
- Jest와 통합: Jest와 함께 사용하여 더 효율적인 테스트 환경을 제공한다.
import { render, screen, fireEvent } from '@testing-library/react';
import MyButton from './MyButton';
test('button click changes text', () => {
render(<MyButton />);
const button = screen.getByRole('button');
fireEvent.click(button);
expect(screen.getByText('Clicked!')).toBeInTheDocument();
});