TDD
TDD(Test-Driven Development는 테스트 주도 개발이라는 소프트웨어 개발 방법론입니다. 개발을 시작하기 전에 테스트를 먼저 작성하고, 그 테스트를 통과하도록 최소한의 코드를 작성한 뒤 점진적으로 기능을 구현하는 방식입니다. TDD는 개발과 테스트를 반복하며 안정성과 품질을 높이는 데 중점을 둡니다.
프로세스
TDD는 Red → Green → Refactor라는 세 단계를 반복합니다
- Red (테스트 실패 상태)
- 새로운 테스트를 작성하지만, 아직 기능이 구현되지 않아 실패합니다.
- 이 단계는 코드 작성의 방향을 정합니다.
- Green (테스트 통과 상태)
- 테스트를 통과할 수 있는 최소한의 코드를 작성합니다.
- 이 단계는 기능이 작동함을 보장합니다.
- Refactor (코드 개선)
- 코드의 중복을 제거하고 가독성을 높이며, 더 나은 설계로 개선합니다.
- 테스트는 여전히 통과해야 합니다.
- 이 단계에서는 기능추가를 하면 안됩니다. (TDD 규칙에 어긋나기 때문에)
장점과 단점
* 장점
- 코드 품질 향상
- 테스트를 기반으로 코드를 작성하기 때문에 안정성이 높고 오류가 줄어듭니다.
- 코드 변경 시 기존 테스트가 동작을 보장해주기 때문에 유지보수가 용이합니다.
- 개발 방향 명확화
- 테스트 작성이 코드 설계의 방향을 정하고, 명확한 목표를 제공합니다.
- 디버깅 시간 감소
- 개발 중 발생하는 오류를 빠르게 탐지하고 수정할 수 있습니다.
* 단점
- 시간 소모
- 테스트 작성과 반복 작업으로 초기 개발 속도가 느릴 수 있습니다.
- 경험 요구
- 테스트 작성 경험과 좋은 테스트 사례를 만들기 위한 역량이 필요합니다.
- 복잡한 테스트 관리
- 테스트가 많아질수록 유지보수가 어려워질 수 있습니다.
Java의 TDD JUnit
JUnit은 Java에서 테스트 주도 개발(TDD)을 지원하는 가장 널리 사용되는 테스트 프레임워크입니다. JUnit을 사용하면 코드의 특정 부분이 올바르게 작동하는지 자동으로 검증할 수 있으며, 반복적인 테스트를 쉽게 수행할 수 있습니다.
* 특징
- 단위 테스트(Unit Test)
- JUnit은 메서드 단위로 코드를 테스트합니다.
- 한 번에 하나의 메서드나 클래스의 동작을 검증합니다.
- 테스트 자동화
- 테스트 코드를 실행하면 예상된 결과와 실제 결과를 자동으로 비교하여 성공/실패를 확인합니다.
- 어노테이션 기반
- 테스트 메서드 작성과 설정이 간단합니다.
- 주요 어노테이션:
- @Test: 테스트 메서드를 정의.
- @BeforeEach / @AfterEach: 테스트 전후 실행할 설정.
- @BeforeAll / @AfterAll: 테스트 클래스 전체에 대한 설정.
- 테스트 리포트
- 테스트 성공/실패 결과를 명확히 출력하여 디버깅을 돕습니다.
- Gradle/Maven 통합
- 빌드 도구와 쉽게 통합되어 CI/CD 환경에서 사용하기 적합합니다.
* 예시
1. 테스트 대상 클래스
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
2. Junit 테스트 클래스
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result); // 예상 결과와 실제 결과 비교
}
@Test
public void testSubtract() {
Calculator calculator = new Calculator();
int result = calculator.subtract(5, 2);
assertEquals(3, result);
}
}
3. Junit 실행 결과
✓ testAdd() - 성공
✓ testSubtract() - 성공
* 예제 : 이메일 검증 로직 작성
1. RED
- 테스트 코드 작성 (테스트는 실패함)
- 아직 구현하지 않은 기능에 대한 테스트를 작성합니다.
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class EmailValidatorTest {
@Test
void testValidEmail() {
EmailValidator validator = new EmailValidator();
boolean isValid = validator.isValid("test@example.com");
assertTrue(isValid, "이메일 형식이 올바르지 않습니다.");
}
}
➡️ 출력
Error: Cannot resolve method 'isValid'
2. Green
- 최소한의 코드를 작성하여 테스트 통과
- 테스트를 통과하도록 필요한 코드만 작성합니다.
public class EmailValidator {
public boolean isValid(String email) {
return true; // 모든 이메일을 유효하다고 가정
}
}
➡️ 출력
Test run finished after 20 ms
[ 1 tests successful ]
3. Refactor
- 코드 리팩토링
- 필요한 경우 가독성, 효율성을 위해 코드를 개선합니다.
import java.util.regex.Pattern;
public class EmailValidator {
private static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";
public boolean isValid(String email) {
return Pattern.matches(EMAIL_REGEX, email); // 정규식으로 이메일 형식 검증
}
}
➡️ 출력
Test run finished after 25 ms
[ 2 tests successful ]
프로젝트 구조
* 서로 다른 package에 있는 main에 있는 class를 test package에서 import 없이 사용할 수 있는 이유?
src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── Calculator.java
├── test/
├── java/
└── com/
└── example/
└── CalculatorTest.java
Java 프로젝트는 일반적으로 두 개의 디렉토리(폴더와 같은 개념) 구조를 사용합니다:
- src/main/java : 애플리케이션의 실제 코드(Production Code)
- src/test/java : 테스트 코드
빌드 도구(예: Maven, Gradle)는 이 구조를 인식하고, src/main/java에 있는 클래스들을 자동으로 테스트 클래스 경로(Classpath)에 포함합니다.
클래스가 자동으로 참조되므로 test package에서는 main package에 있는 class를 import 하지 않아도 됩니다.
TDD 요약
- 테스트를 먼저 작성하고, 이를 통해 요구사항을 명확히 정의
- 실패하는 테스트에서 시작하여, 테스트를 통과하는 코드를 점진적으로 작성
- 리팩터링을 통해 코드 품질과 유지보수성을 높임
- 인생은 TDD 처럼
참고하면 좋은 사이트
1. 유튜브 참고 영상 : 우아한 테크
출처
OpenAI의 ChatGPT (https://openai.com)
TDD 이미지 출처 : https://hanamon.kr/tdd란-테스트-주도-개발/
TDD란? 테스트 주도 개발 - 하나몬
TDD란 Test Driven Development의 약자로 '테스트 주도 개발'이라고 한다.
hanamon.kr
TDD 프로세스 이미지 출처 : https://jimmy7525.tistory.com/m/86
TDD - UI Test
테스트 주도 개발 TDD (Test-Driven Development) 은 매우 짧은 개발 사이클을 반복하는 소프트웨어 개발 프로세스 중 하나이다. 개발자는 먼저 요구 사항을 검증하는 자동화 된 테스트 케이스를 작성한
jimmy7525.tistory.com
'CS > CS' 카테고리의 다른 글
버퍼 (Buffer) (0) | 2025.01.04 |
---|---|
메서드 체이닝(Method Chaining) (0) | 2024.12.05 |
명령형(imperative) VS 선언형(declarative) 프로그래밍 (1) | 2024.12.05 |
레이어드 아키텍처 응용 (Layered Architecture) (0) | 2024.12.03 |
Software Architecture (소프트웨어 아키텍처) (0) | 2024.11.26 |