Post

08 SpringTest

08 SpringTest

1. SpringTest

1. Junit - SpringTest - SpringBootTest

구분역할관계
JUnit자바에서 단위 테스트를 작성하고 실행하기 위한 테스트 프레임워크스프링과 무관하게 단독으로 사용 가능
Spring Test (스프링 테스트 모듈)스프링 컨테이너, 빈, 트랜잭션 등을 테스트 환경에서 제어할 수 있게 도와주는 확장 도구내부적으로 JUnit 위에서 동작
Spring Boot Test@SpringBootTest, @MockBean, @DataJpaTest 등 통합 테스트 지원 기능 제공Spring Test + Boot 환경 통합 버전

2. JUnit 구성요소

구성 요소설명주요 역할특징
JUnit Platform테스트 실행의 기반 엔진테스트를 실행하고 관리하는 환경 제공 (IDE, Gradle, Maven 등과 연동)테스트 엔진을 탐색하고 실행 결과를 리포팅함
JUnit JupiterJUnit 5의 핵심 API 모듈우리가 사용하는 @Test, @BeforeEach, Assertions 등 실제 기능 제공JUnit 5 스타일 테스트 작성 시 기본적으로 사용하는 부분
JUnit Vintage이전 버전(JUnit 3, 4) 테스트 호환 모듈기존 프로젝트의 레거시 테스트 코드 실행 지원JUnit 5 환경에서도 JUnit 4 테스트를 함께 돌릴 수 있음

2. JUnit Jupiter가 제공하는 애노테이션

1. 테스트 생명주기 관련 애노테이션

어노테이션설명
@BeforeAll테스트 클래스 시작 전에 한 번 실행 (ex. DB 연결 설정)
@BeforeEach각 테스트 실행 전마다 실행 (ex. 테스트 초기화)
@Test실제 테스트 코드
@AfterEach각 테스트 실행 후마다 실행 (ex. 리소스 정리)
@AfterAll모든 테스트 종료 후 한 번만 실행

2. 단언(Assertion) API

메서드설명
assertEquals(expected, actual)예상값과 실제값이 같은지
assertTrue(condition) / assertFalse(condition)조건이 참/거짓인지
assertThrows(Exception.class, () -> { ... })특정 예외 발생 여부 확인
assertAll()여러 검증을 한꺼번에 실행
assertNotNull(obj)객체가 null이 아닌지 확인

3. 테스트 조건 제어

어노테이션설명
@Disabled특정 테스트 비활성화
@EnabledOnOs(OS.WINDOWS)특정 운영체제에서만 실행
@EnabledIfEnvironmentVariable()환경 변수 조건에 따라 실행 여부 결정

4. 테스트 반복 파라미터

어노테이션설명
@RepeatedTest(5)동일한 테스트를 여러 번 반복
@ParameterizedTest여러 입력값으로 같은 테스트를 반복
@ValueSource(strings = {"a", "b", "c"})파라미터화 테스트용 값 지정

5. 태깅 및 그룹화

어노테이션설명
@Tag("fast"), @Tag("integration")테스트를 분류할 때 사용
@DisplayName("사용자 등록 기능 테스트")테스트 설명을 사람이 읽기 좋게 표시

3. 스프링 프레임워크와 스프링부트 테스트

1. 스프링 프레임워크, 스프링부트

구분Spring Framework TestSpring Boot Test
제공 주체Spring FrameworkSpring Boot
주요 패키지org.springframework.test.org.springframework.boot.test.
테스트 목적스프링 컨테이너, 빈 주입, 트랜잭션 등 핵심 기능 검증스프링부트 애플리케이션 전체 또는 특정 계층 테스트 간소화
환경순수 스프링 환경 (부트 의존 X)스프링부트 프로젝트 환경 (Auto Configuration 활용)
대표 어노테이션@ContextConfiguration, @WebAppConfiguration, @Transactional@SpringBootTest, @WebMvcTest, @DataJpaTest, @MockBean, @SpyBean
주요 도구/클래스MockMvc, TestContext, ApplicationContextSpringBootContextLoader, SpringBootTestContextBootstrapper
설정 방식설정 파일(XML 또는 Java Config)을 직접 지정스프링부트 설정을 자동으로 로드 (간단함)
테스트 범위특정 Bean, 트랜잭션, 컨텍스트 레벨애플리케이션 전체 또는 특정 계층 단위 (MVC, JPA 등)
특징• 테스트 인프라 제공 (핵심 기능 중심)
• 구성 복잡하지만 유연함
• 자동 설정 기반, 작성 간편
• 실제 서비스 환경에 가까운 테스트 가능

2. Spring FrameWork Test

주요 어노테이션설명
@ContextConfiguration테스트에서 사용할 스프링 설정 파일(XML/Java Config) 지정
@WebAppConfiguration웹 애플리케이션 환경 테스트 설정
@Transactional테스트 실행 후 트랜잭션 롤백 처리
@RunWith(SpringRunner.class) (JUnit4)스프링 테스트 컨텍스트와 통합 실행
@TestPropertySource테스트 환경에서 사용할 프로퍼티 지정

3. 스프링부트 애노테이션

분류목적주요 어노테이션
전체 애플리케이션 통합 테스트애플리케이션 전체를 띄워 통합적으로 테스트@SpringBootTest
계층별 테스트 (Test Slices)특정 계층만 독립적으로 테스트@WebMvcTest, @DataJpaTest, @JdbcTest, @DataJdbcTest, @RestClientTest, @JsonTest, @WebFluxTest
테스트 환경 설정 및 구성테스트 실행 환경 조정 및 설정 추가@TestConfiguration, @TestPropertySource, @DynamicPropertySource, @ActiveProfiles, @DirtiesContext, @AutoConfigureTestDatabase
Mock / Spy 관련 테스트 지원의존성 모킹 및 스파잉@MockBean, @SpyBean, @MockitoBean, @MockitoSpyBean

4. AssertTJ

1. AssertJ

  • Java용 Fluent Assertion 라이브러리
  • 테스트에서 결과를 검증하는 강력하고 직관적인 API 제공
  • 자연어처럼 읽히는 문법(Fluent API) 지원
  • spring-boot-starter-test에 기본 포함돼 있어서 스프링부트에서 바로 사용 가능

2. 검증 메소드

1. 분류

분류검증 메소드설명
기본 비교isEqualTo(expected)실제 값이 기대 값과 같은지 검증
 isNotEqualTo(expected)실제 값이 기대 값과 다름을 검증
 isSameAs(expected)실제 값이 동일 객체인지 검증
 isNotSameAs(expected)실제 값이 동일 객체가 아님을 검증
널/불리언 검증isNull()값이 null인지 검증
 isNotNull()값이 null이 아님을 검증
 isTrue()값이 true인지 검증
 isFalse()값이 false인지 검증
숫자 검증isGreaterThan(value)실제 값이 주어진 값보다 큰지 검증
 isLessThan(value)실제 값이 주어진 값보다 작은지 검증
 isBetween(start, end)값이 범위 안에 있는지 검증
 isPositive(), isNegative()값이 양수/음수인지 검증
문자열 검증startsWith(prefix)문자열이 특정 접두사로 시작하는지 검증
 endsWith(suffix)문자열이 특정 접미사로 끝나는지 검증
 contains(substring)문자열에 특정 내용이 포함되는지 검증
 matches(regex)정규식과 일치하는지 검증
컬렉션 검증hasSize(size)컬렉션의 크기가 특정 값인지 검증
 contains(element)컬렉션이 특정 요소를 포함하는지 검증
 containsExactly(elements)요소 순서와 내용까지 일치하는지 검증
 isEmpty(), isNotEmpty()컬렉션이 비어 있는지/비어 있지 않은지 검증
예외 검증isInstanceOf(Exception.class)예외 타입 검증
 hasMessageContaining(text)예외 메시지에 특정 문자열 포함 여부 검증
옵셔널(Optional) 검증isPresent()Optional 값이 존재하는지 검증
 isEmpty()Optional 값이 비어있는지 검증
 contains(value)Optional 값이 특정 값을 포함하는지 검증

2. 테스트

1. 체크

1
2
3
4
5
6
7
8
9
  import static org.assertj.core.api.Assertions.assertThat;
  
  @Test
  void exampleTest() {
      int result = 2 + 2;
  
      assertThat(result).isEqualTo(4);  // true → 테스트 통과
      assertThat(result > 5).isTrue(); // false → AssertionError 발생, 테스트 실패
  }

2. 체이닝

1
2
3
4
5
6
7
8
9
10
11
12
    import static org.assertj.core.api.Assertions.assertThat;

    @Test
    void chainingExample() {
        String name = "홍길동";
    
        assertThat(name)
            .isNotNull() // .isNotNull() → null 여부 확인
            .startsWith("홍") // .startsWith("홍") → 문자열 시작 여부 확인
            .contains("길") // .contains("길") → 특정 문자열 포함 여부 확인
            .endsWith("동"); // .endsWith("동") → 문자열 끝 여부 확인
    }

3. 결과값

1. 결과값

  • AssertJ는 기본적으로 실패 시 기대값 vs 실제값 비교 메시지를 자동 생성
  • 메시지를 따로 지정하지 않으면 AssertJ가 제공하는 기본 메시지가 출력됨

2. 일반 실패

  • Case
    1
    
     assertThat(2 + 2).isEqualTo(5);
    
  • 실패로그
    1
    2
    3
    4
    5
    
      Expecting:
      <4>
      to be equal to:
      <5>
      but was not.
    

3. 커스텀 실패

  • Case
    1
    2
    3
    
     assertThat(2 + 2)
      .withFailMessage("계산 결과가 예상과 다릅니다. 실제값: %s", 2 + 2)
      .isEqualTo(5);
    
  • 실패로그
    1
    2
    3
    4
    5
    6
    
     계산 결과가 예상과 다릅니다. 실제값: 4
     Expecting:
     <4>
     to be equal to:
     <5>
     but was not.
    

5. 실제 테스트 예시

1. AssertJ & Junit

구분JUnitAssertJ
역할테스트 실행 프레임워크Assertion 라이브러리
주요 기능테스트 메서드 실행, 라이프사이클 관리 (@Test, @BeforeEach, @AfterEach)테스트 결과 검증 (assertThat, isEqualTo, isNotNull 등)
문법 스타일assertEquals(expected, actual)assertThat(actual).isEqualTo(expected)
가독성다소 직관적이지 않음자연어에 가까운 가독성
확장성제한적풍부하고 직관적인 검증 API 제공
지원 데이터 타입단순 비교문자열, 컬렉션, 객체, 예외 등 다양한 타입 검증
객체 검증제한적필드 단위 검증, 복잡 객체 비교 가능
실무 트렌드테스트 실행용으로 사용검증 로직은 대부분 AssertJ로 작성
대표 메서드assertEquals, assertTrue, assertFalse, assertNullassertThat, isEqualTo, isNotNull, contains, hasSize 등
의존성JUnit 라이브러리AssertJ 라이브러리 (spring-boot-starter-test에 포함)

2. 클래스 위치

  • 테스트 코드 위치: src/test/java/
  • 테스트 패키지: 보통 실제 코드 패키지 구조를 그대로 복제 예: 실제 코드 com.example.demo.service → 테스트 코드 com.example.demo.service
  • 이유: 이렇게 하면 테스트가 해당 코드와 논리적으로 연결되고, IDE나 빌드 도구(Gradle/Maven)가 자동으로 테스트를 찾음
  • Package
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    src/
     ├── main/
     │    ├── java/
     │    │    └── com/example/demo/   ← 실제 코드
     │    └── resources/
     └── test/
          ├── java/
          │    └── com/example/demo/   ← 테스트 코드
          └── resources/
    

3. 서비스 로직 테스트

1. 서비스클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  package com.example.demo.service;
  
  import org.springframework.stereotype.Service;
  
  @Service
  public class CalculatorService {
      public int add(int a, int b) {
          return a + b;
      }
  
      public int subtract(int a, int b) {
          return a - b;
      }
  }

2. 테스트 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  package com.example.demo;
  
  import com.example.demo.service.CalculatorService;
  import org.junit.jupiter.api.Test;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.boot.test.context.SpringBootTest;
  
  import static org.assertj.core.api.Assertions.assertThat;
  
  @SpringBootTest
  class CalculatorServiceTest {
  
      @Autowired
      private CalculatorService calculatorService;
  
      @Test
      void testAdditionAndSubtraction() {
          int sum = calculatorService.add(5, 3);
          int difference = calculatorService.subtract(5, 3);
  
          assertThat(sum)
              .isEqualTo(8)
              .isPositive()
              .isGreaterThan(7);
  
          assertThat(difference)
              .isEqualTo(2)
              .isPositive()
              .isLessThan(5);
      }
  }

3. 결과값

  • 성공
    1
    2
    
    BUILD SUCCESS
     Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
  • 실패
    1
    2
    3
    4
    5
    6
    
    org.opentest4j.AssertionFailedError:
     Expecting:
     <9>
     to be equal to:
     <8>
     but was not.
    
This post is licensed under CC BY 4.0 by the author.