테스트 주도 개발(Test-Driven Development, TDD)은 소프트웨어 개발 방법론 중 하나로, 테스트 코드를 먼저 작성한 후 실제 코드를 작성하는 방식이다. 이런 방식은 버그를 줄이고 수정하는데 도움이 된다.
TDD의 주요 단계
1. 테스트를 실패하는 코드 작성
새로운 기능이나 수정할 기능에 대해 실패하는 작은 단위 테스트를 작성
2. 테스트를 통과하는 최소한의 코드 작성
빠르게 테스트를 통과하는 간단하고 명확한 코드를 작성
3. 리팩토링
코드의 중복을 제거하고 최적화
TDD의 대표적인 프레임워크 'JUnit'
JUnit은 Java 애플리케이션의 단위 테스트를 위해 널리 사용되는 프레임워크이다. 현재 JUnit5 버전이 가장 널리 사용되고 있다.
단위 테스트란 가장 작은 단위(보통 함수나 메서드)를 개별적으로 테스트하여 올바르게 동작하는지 확인하는 것이다.
단위 테스트는 독립적으로 실행되기 때문에 테스트 중 발생하는 각각의 문제를 빠르게 발견하고 수정할 수 있다. 통합 테스트는 여러 단위(모듈)의 상호작용 확인하기 때문에 프로젝트의 규모가 크면 클수록 시간이 오래 걸리기 때문에 단위 테스트가 특히 더 중요하다.
이전 JUnit 버전과 다르게, JUnit5는 세개의 모듈로 구성되어있다.
JUnit Platform + JUnit Jupiter + JUnit Vintage
- JUnit Platform - 테스트를 실행하고, 결과를 보고하며, 다양한 테스트 프레임워크와 엔진을 지원하는 기반을 제공
- JUnit Jupiter - JUnit 5에서 새로운 테스트 프로그래밍 모델과 확장 모델을 제공하는 모듈
- JUnit Vintage - JUnit 3와 JUnit 4 기반의 테스트를 JUnit 5 환경에서 실행할 수 있도록 지원하는 모듈
JUnit5의 전반적인 흐름
1. 개발자가 빌드 도구나 IDE에서 테스트 실행을 요청
2. JUnit Platform 내에서 테스트 코드가 수행됨
3. 테스트를 적절한 테스트 엔진(JUnit Jupiter 또는 JUnit Vintage)에서 실행
4. 각 테스트 엔진이 테스트를 실행하고 결과를 수집
5. JUnit Platform이 테스트 실행 결과를 콘솔, 리포트 파일, 또는 IDE에 전달
Spring에서 TDD를 적용해보는 예제 (JUnit5)
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class MemoryMemberRepositoryTest {
MemoryMemberRepository repository = new MemoryMemberRepository();
@AfterEach
public void afterEach() {
repository.clearStore();
}
@Test //테스트 메소드임을 나타내는 어노테이션
public void save() {
Member member = new Member();
member.setName("spring");
repository.save(member);
Member result = repository.findById(member.getId()).get();
// Assertions.assertEquals(member, result);
assertThat(member).isEqualTo(result);
}
@Test
public void findByName() {
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
Member result = repository.findByName("spring1").get();
// Assertions.assertEquals(member1, result);
assertThat(result).isEqualTo(member1);
}
@Test
public void findAll() {
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
List<Member> result = repository.findAll();
assertThat(result.size()).isEqualTo(2);
}
}
MemoryMemberRepository 클래스를 테스트 대상으로 하여 주요 메서드(save, findByName, findAll)가 예상대로 동작하는지 확인 하고있다. 각 테스트 메서드는 특정 기능을 검증하며, 테스트가 완료된 후 @AfterEach 어노테이션을 통해 리포지토리를 초기화하여 다른 테스트에 영향을 미치지 않도록 한다.
* 위 코드에서 사용된 JUnit 관련 어노테이션과 메소드는 아래 사이트를 참고
JUnit5 어노테이션
https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
JUnit 5 User Guide
Although the JUnit Jupiter programming model and extension model do not support JUnit 4 features such as Rules and Runners natively, it is not expected that source code maintainers will need to update all of their existing tests, test extensions, and custo
junit.org
JUnit5 Assertions 메소드
https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html
Assertions (JUnit 5.0.1 API)
Asserts that all supplied executables do not throw exceptions. If any supplied Executable throws an exception (i.e., a Throwable or any subclass thereof), all remaining executables will still be executed, and all exceptions will be aggregated and reported
junit.org
'백엔드 TIL' 카테고리의 다른 글
[Docker] 도커란? 도커파일(Docker File) 개념과 작성법 (0) | 2024.07.30 |
---|---|
[OOP] 객체 지향 프로그래밍이란? (0) | 2024.07.11 |
[Spring] Spring과 좋은 객체 지향 프로그래밍에 대해서 (0) | 2024.07.09 |