출시·고도화 중
Spring Boot 안내서 · 5/6
Spring Boot는 JUnit Jupiter, AssertJ, Mockito, Spring Test를 묶어 제공하고, 애플리케이션의 일부만 띄우는 슬라이스 테스트와 전체를 띄우는 통합 테스트를 모두 지원합니다. 이 장에서는 테스트를 빠른 것부터 느린 것 순서로 살펴봅니다.
Initializr가 만든 프로젝트에는 기술별 테스트 스타터(spring-boot-starter-webmvc-test, spring-boot-starter-data-jpa-test 등)가 들어 있습니다. 테스트는 빌드 도구로 실행합니다.
./gradlew test
./mvnw test
# 클래스 하나만 실행
./gradlew test --tests "com.example.demo.todo.TodoServiceTests"생성자 주입을 쓰면 Spring 없이도 객체를 직접 만들어 테스트할 수 있습니다. 가장 빠르므로 비즈니스 규칙은 이렇게 검사하는 것이 좋습니다.
class GreetingServiceTests {
@Test
void greetsInTheMorning() {
Clock morning = Clock.fixed(Instant.parse("2025-01-01T08:00:00Z"), ZoneOffset.UTC);
GreetingService service = new GreetingService(morning);
assertThat(service.greet("Kim")).isEqualTo("Good morning, Kim");
}
}@WebMvcTest는 컨트롤러, JSON 변환, 검증 같은 MVC 구성만 띄우고 서비스나 저장소는 등록하지 않습니다. 컨트롤러가 의존하는 빈은 @MockitoBean으로 가짜 객체를 넣습니다. MockMvcTester는 AssertJ 스타일로 요청과 응답을 검사합니다.
@WebMvcTest(TodoController.class)
class TodoControllerTests {
@Autowired
MockMvcTester mvc;
@MockitoBean
TodoService service;
@Test
void returnsTodo() {
given(service.find(1L)).willReturn(new TodoResponse(1L, "Write docs", false));
assertThat(mvc.get().uri("/api/todos/1"))
.hasStatusOk()
.bodyJson().extractingPath("$.title").isEqualTo("Write docs");
}
@Test
void rejectsBlankTitle() {
assertThat(mvc.post().uri("/api/todos")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"title\": \"\"}"))
.hasStatus(HttpStatus.BAD_REQUEST);
}
}이전 세대에서는 @MockBean을 썼지만, 지금은 Spring Framework의 @MockitoBean으로 바뀌었습니다.
@DataJpaTest는 JPA 관련 빈만 구성하고, 각 테스트를 트랜잭션 안에서 실행한 뒤 롤백합니다. 클래스 경로에 내장 데이터베이스(H2 등)가 있으면 기본적으로 그것으로 바꿔 씁니다. 아래 예제를 그대로 돌리려면 testRuntimeOnly("com.h2database:h2")를 추가하거나, 다음 절처럼 Testcontainers를 씁니다.
@DataJpaTest
class TodoRepositoryTests {
@Autowired
TestEntityManager entityManager;
@Autowired
TodoRepository repository;
@Test
void findsOpenTodos() {
entityManager.persist(new Todo("open"));
Todo done = new Todo("done");
done.complete();
entityManager.persist(done);
assertThat(repository.findByDoneFalseOrderByIdAsc())
.extracting(Todo::getTitle)
.containsExactly("open");
}
}@SpringBootTest는 실제 애플리케이션과 같은 컨텍스트를 띄웁니다. MockMvc가 필요하면 @AutoConfigureMockMvc를 함께 붙입니다. 실제 포트로 서버를 띄우려면 webEnvironment = WebEnvironment.RANDOM_PORT를 지정합니다.
운영과 같은 데이터베이스로 테스트하려면 Testcontainers를 씁니다. Docker로 컨테이너를 띄우고, @ServiceConnection이 연결 정보를 자동으로 설정해 주므로 spring.datasource.url을 따로 적지 않아도 됩니다.
@Testcontainers
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class TodoRepositoryPostgresTests {
@Container
@ServiceConnection
static PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:alpine");
@Autowired
TodoRepository repository;
@Test
void savesTodo() {
Todo saved = repository.save(new Todo("from container"));
assertThat(saved.getId()).isNotNull();
}
}@AutoConfigureTestDatabase(replace = NONE)은 내장 데이터베이스로 바꾸지 말고 컨테이너를 쓰라는 뜻입니다. 이때 Flyway 마이그레이션도 컨테이너에 그대로 적용됩니다. Initializr에서 testcontainers를 고르면 TestcontainersConfiguration과 TestDemoApplication이 함께 만들어지며, ./gradlew bootTestRun(Maven은 ./mvnw spring-boot:test-run)으로 개발 중에도 컨테이너 데이터베이스를 붙여 앱을 실행할 수 있습니다.
@WebMvcTest와 @MockitoBean, 데이터 계층은 @DataJpaTest로 잘라서 테스트합니다.@SpringBootTest로 확인합니다.@ServiceConnection으로 실제 데이터베이스를 손쉽게 붙입니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.