자바 백엔드 입문 52편 — @SpringBootTest 통합 테스트

2026-05-16자바 백엔드 입문

자바 백엔드 입문 52편. Phase 7 Testing 시작. @SpringBootTest로 Spring 컨테이너를 띄우고 실제 Bean들로 통합 테스트하는 표준 패턴을 모의 비행 시뮬레이터 비유로 풀어쓴 학습 노트.

📚 자바 백엔드 입문 · 52편 — @SpringBootTest 통합 테스트

이 글은 자바 백엔드 입문 시리즈 59편 중 52편이에요. Phase 6.5 JPA 4편이 끝났고, 이번 52편부터 Phase 7 Testing 2편으로 들어갑니다. 코드를 짜는 것만큼 중요한 "내가 짠 게 진짜 동작하는가 자동 검증" 의 표준 패턴.

통합 테스트가 어렵게 들리는 이유

처음 "Spring Boot 테스트" 를 검색하면 — @SpringBootTest·@WebMvcTest·@DataJpaTest·@MockBean·@Autowired 같은 어노테이션이 한꺼번에 쏟아져요. 무엇을 언제 써야 할지 안 잡혀요.

이 글에서는 모의 비행 시뮬레이터 비유로 풀어요. 단위 테스트 = "비행기 한 부품만 따로 테스트", 통합 테스트 = "전체 비행기를 시뮬레이터에 띄워 실제 비행 시험". @SpringBootTest 가 그 시뮬레이터예요. 끝까지 따라오시면 5종 테스트 어노테이션이 한 그림에 들어와요.

테스트 의존성 — 자동 포함

Spring Boot 프로젝트는 spring-boot-starter-test 가 자동 포함돼요. 이 한 줄에 다음이 다 들어 있어요.

  • JUnit 5 — 테스트 프레임워크
  • AssertJ — 검증 표현 라이브러리
  • Mockito — 모의 객체 라이브러리
  • Spring Test — Spring 전용 테스트 지원
  • Spring Boot Test — Spring Boot 전용 테스트 지원
dependencies {
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

별도 설정 없이 위 5개 도구가 자동 동작 준비.

첫 통합 테스트 — @SpringBootTest

가장 단순한 통합 테스트 골격.

@SpringBootTest
class OrderServiceIntegrationTest {

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderRepository orderRepository;

    @Test
    void 주문_생성_후_조회() {
        // Given
        OrderRequest request = new OrderRequest(1L, 10000, "Alice");

        // When
        Order saved = orderService.create(request);
        Order found = orderRepository.findById(saved.getId()).get();

        // Then
        assertThat(found.getAmount()).isEqualTo(10000);
        assertThat(found.getStatus()).isEqualTo("PENDING");
    }
}

이 테스트가 실행되면 — @SpringBootTest 가 실제 Spring 컨테이너를 띄움. @Autowired 로 진짜 Service·Repository Bean을 받아서 "운영과 똑같은 환경" 에서 동작 검증. 가장 신뢰성 높은 테스트.

테스트 작성 표준 — Given·When·Then

테스트 한 메서드 안에 세 부분 명시.

@Test
void 메서드명() {
    // Given — 테스트 사전 조건 세팅
    OrderRequest request = ...;

    // When — 검증 대상 동작 실행
    Order saved = orderService.create(request);

    // Then — 결과 검증
    assertThat(saved.getId()).isNotNull();
}

세 단어 그대로 주석에 박는 게 한국 회사 표준. 테스트 메서드 이름은 한국어로 "무엇을 검증하는지" 명확히 — 주문_생성_후_상태_확인() 같이.

AssertJ — 검증 표현

표준 JUnit assertEquals(expected, actual) 보다 가독성 좋은 AssertJ.

// JUnit 표준
assertEquals(10000, order.getAmount());
assertTrue(order.getStatus().equals("PENDING"));

// AssertJ (권장)
assertThat(order.getAmount()).isEqualTo(10000);
assertThat(order.getStatus()).isEqualTo("PENDING");
assertThat(order.getCreatedAt()).isAfter(LocalDateTime.now().minusMinutes(1));
assertThat(orderRepository.findAll())
        .hasSize(3)
        .extracting(Order::getStatus)
        .containsExactly("PENDING", "PAID", "SHIPPED");

체이닝으로 검증이 자연스러워요. 메서드 이름이 거의 영어 문장처럼 읽혀요. spring-boot-starter-test 에 자동 포함.

@SpringBootTest의 무게 — 느림

@SpringBootTest실제 Spring 컨테이너를 띄우는 무거운 테스트. 한 번 시동에 1~10초 걸려요. 모든 테스트에 박으면 — 테스트 100개가 10분 넘게 걸릴 수도.

해결 — "Spring 전체가 필요 없는 테스트는 더 가벼운 어노테이션" 사용.

Slice 테스트 — 일부 영역만 띄우기

Spring Boot가 제공하는 "슬라이스(Slice) 테스트" 어노테이션.

어노테이션 띄우는 영역 사용
@SpringBootTest 전체 컨테이너 E2E·통합
@WebMvcTest Controller·MVC 부품만 컨트롤러 단위
@DataJpaTest JPA Repository + 인메모리 DB Repository 단위
@JsonTest Jackson 직렬화만 JSON 변환 검증
@RestClientTest RestTemplate·WebClient만 외부 API 호출
@WebMvcTest(OrderController.class)
class OrderControllerTest {

    @Autowired private MockMvc mockMvc;
    @MockBean private OrderService orderService;   // 진짜 Service는 안 띄움

    @Test
    void 주문_조회() throws Exception {
        when(orderService.findById(1L)).thenReturn(new Order(1L, 10000, "PENDING"));

        mockMvc.perform(get("/orders/1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.amount").value(10000));
    }
}

@WebMvcTest"OrderController에 필요한 Web 부품만" 띄워요. Service·Repository는 안 띄워서 — 2~3배 빠름. MockMvc 로 HTTP 요청 흉내 + @MockBean 으로 Service를 가짜 객체로 대체.

@DataJpaTest — Repository 전용

JPA Repository만 테스트하고 싶을 때.

@DataJpaTest
class OrderRepositoryTest {

    @Autowired private OrderRepository orderRepository;
    @Autowired private TestEntityManager em;

    @Test
    void 상태별_주문_조회() {
        // Given
        em.persistAndFlush(new Order(null, 10000, "PENDING"));
        em.persistAndFlush(new Order(null, 20000, "PENDING"));
        em.persistAndFlush(new Order(null, 30000, "COMPLETED"));

        // When
        List<Order> pending = orderRepository.findByStatus("PENDING");

        // Then
        assertThat(pending).hasSize(2);
    }
}

@DataJpaTest 가 자동으로 — 인메모리 H2 DB로 교체 + JPA만 띄움. 진짜 PostgreSQL 없이도 빠르게 Repository 테스트. 테스트 후 자동 롤백 도 보너스.

@MockBean — 가짜 Bean으로 교체

특정 의존성을 "진짜 Bean 대신 가짜" 로 바꾸고 싶을 때.

@SpringBootTest
class OrderServiceTest {

    @Autowired private OrderService orderService;

    @MockBean
    private PaymentGateway paymentGateway;   // 진짜 결제 게이트웨이 대신 가짜

    @Test
    void 결제_실패_시_주문_롤백() {
        // Given — 가짜 결제 게이트웨이가 예외 던지도록
        when(paymentGateway.charge(any())).thenThrow(new PaymentFailedException());

        // When + Then
        assertThatThrownBy(() -> orderService.placeOrder(new OrderRequest(...)))
                .isInstanceOf(PaymentFailedException.class);
    }
}

진짜 카카오페이·토스에 안 가고 — 우리가 정의한 동작(예외 던지기·특정 값 반환)으로 가짜 처리. Mockitowhen(...).thenReturn(...) / when(...).thenThrow(...) 패턴.

@Transactional 테스트 — 자동 롤백

테스트 메서드에 @Transactional 박으면 — 테스트 후 모든 DB 변경 자동 롤백.

@SpringBootTest
@Transactional
class OrderServiceIntegrationTest {

    @Test
    void test1() {
        orderRepository.save(new Order(...));   // INSERT
        // ↓ 테스트 끝나면 자동 ROLLBACK
    }

    @Test
    void test2() {
        // test1의 영향 없음 — DB 깨끗한 상태
    }
}

테스트 간 격리 + DB 오염 방지. @SpringBootTest 와 함께 박는 게 표준 패턴.

테스트 프로파일 — application-test.yml

테스트 전용 설정을 따로 두는 게 표준.

# src/test/resources/application-test.yml
spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
  jpa:
    hibernate:
      ddl-auto: create-drop
@SpringBootTest
@ActiveProfiles("test")              // test 프로파일 활성
class IntegrationTest { ... }

운영 PostgreSQL 대신 — 테스트는 H2 인메모리로. CI 환경에서 DB 없이도 테스트 실행 가능.

🎯 테스트 어노테이션 선택 룰

전체 흐름 검증@SpringBootTest. Controller·HTTP@WebMvcTest. JPA Repository@DataJpaTest. 순수 Service 로직 → 어노테이션 X + Mockito 단위 테스트. 가장 가벼운 게 가장 빠름.

한 줄 정리 — @SpringBootTest = 전체 Spring 컨테이너 띄우는 통합 테스트. 무거운 만큼 신뢰성 높음. 가벼운 슬라이스 테스트(@WebMvcTest·@DataJpaTest)와 조합. @MockBean 으로 외부 의존성 대체, @Transactional 로 자동 롤백.

시험 직전 한 번 더 — 통합 테스트 입문자가 매번 헷갈리는 것

  • spring-boot-starter-test 한 줄 = JUnit 5·AssertJ·Mockito·Spring Test 다 포함
  • @SpringBootTest = 전체 Spring 컨테이너 띄우는 통합 테스트
  • 무거움 (1~10초 시동) — 모든 테스트에 박지 X
  • 슬라이스 테스트 = 일부 영역만 띄워 빠르게
  • @WebMvcTest = Controller·MVC만
  • @DataJpaTest = JPA Repository + 인메모리 H2
  • @JsonTest = Jackson 직렬화만
  • @RestClientTest = REST 클라이언트만
  • 표준 패턴 = Given·When·Then 주석
  • 메서드 이름 = 한국어로 "무엇을 검증" 명확히
  • AssertJ = assertThat(...).isEqualTo(...) 체이닝
  • MockMvc = HTTP 요청 흉내 (실제 Tomcat 안 띄움)
  • @MockBean = 진짜 Bean 대신 가짜
  • Mockito = when(...).thenReturn(...) / when(...).thenThrow(...)
  • 가짜 객체로 외부 의존성(결제·이메일) 차단
  • @Transactional 테스트 = 자동 롤백
  • 테스트 간 격리 + DB 오염 방지
  • @ActiveProfiles("test") = 테스트 전용 설정 활성
  • application-test.yml = 테스트 DB·캐시 설정 분리
  • 인메모리 H2 = 운영 PostgreSQL 대체 빠른 테스트
  • 가장 빠른 단위 테스트 = Spring 어노테이션 X + Mockito만

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!