[Spring] 통합 테스트와 단위 테스트 패키징 방법

김민범·2024년 12월 14일

Spring

목록 보기
24/29

통합 테스트의 패키지 구성

스프링 통합 테스트 패키지 구성테스트의 목적과 범위에 따라 결정되는 것이 좋다. 통합 테스트는 단위 테스트와는 다른 범위를 검증하므로, 코드와 테스트를 체계적으로 관리하기 위해 패키지 구조를 구분하는 것이 적합하다.

아래는 통합 테스트를 위한 패키징을 구성하는 방법과 그 이유에 대해 설명한다.


1. 기본 패키징 원칙

  1. 테스트 코드와 실제 코드는 분리하는 것이 좋다

    • 일반적으로 src/main/javasrc/test/java를 분리하여 테스트와 실제 코드를 관리하는 것이 적합하다.
    • 통합 테스트는 src/test/java에 위치시키는 것이 좋다.
  2. 단위 테스트와 통합 테스트의 패키지는 구분하는 것이 좋다

    • 단위 테스트와 통합 테스트는 목적과 실행 환경이 다르므로, 각각 별도의 패키지를 사용하는 것이 적합하다.
    • 예를 들어 아래와 같은 구조로 나누는 것이 좋다.
      src/test/java
      ├── com.example.project
      │   ├── unit      # 단위 테스트
      │   │   ├── service
      │   │   ├── controller
      │   │   └── repository
      │   ├── integration # 통합 테스트
      │   │   ├── service
      │   │   ├── controller
      │   │   └── repository
  3. 실제 코드와 동일한 패키지 구조를 사용하는 것이 좋다

    • 테스트 클래스는 일반적으로 실제 클래스와 동일한 패키지 경로에 위치하여 접근성을 유지하는 것이 적합하다.
    • 단위 테스트와 통합 테스트의 디렉토리를 별도로 나누되, 테스트 클래스의 경로는 실제 코드와 일치시키는 것이 좋다.

2. 패키지 구조 설계: 예제

실제 코드 구조

src/main/java
└── com.example.project
    ├── controller
    ├── service
    └── repository

단위 테스트 구조

src/test/java
└── com.example.project
    ├── unit
    │   ├── controller
    │   ├── service
    │   └── repository

통합 테스트 구조

src/test/java
└── com.example.project
    ├── integration
    │   ├── controller
    │   ├── service
    │   └── repository

이 구조는 다음과 같은 장점을 제공하는 것이 적합하다:
1. 가독성을 높인다: 단위 테스트와 통합 테스트가 구분되어 각 테스트의 목적이 명확해지는 것이 좋다.
2. 접근성을 유지한다: 테스트 클래스가 실제 클래스와 동일한 패키지 구조를 따르므로, 패키지 전용 접근제어자(package-private)를 사용하는 코드에도 접근할 수 있는 것이 적합하다.
3. 유지보수성을 향상시킨다: 패키지 구조가 일관되므로, 코드 변경 시 관련 테스트를 쉽게 찾을 수 있는 것이 좋다.


3. 통합 테스트의 패키지 구분 방법

3.1 기능별로 구분하는 것이 좋다

통합 테스트를 기능별로 분류하는 방식은 아래와 같다.

src/test/java
└── com.example.project.integration
    ├── UserIntegrationTest.java    # User 관련 통합 테스트
    ├── ItemIntegrationTest.java    # Item 관련 통합 테스트
    ├── OrderIntegrationTest.java   # Order 관련 통합 테스트

3.2 레이어별로 구분하는 것이 좋다

테스트 대상을 애플리케이션 레이어(Controller, Service, Repository) 기준으로 구분하는 방식은 아래와 같다.

src/test/java
└── com.example.project.integration
    ├── controller
    │   ├── UserControllerIntegrationTest.java
    │   └── ItemControllerIntegrationTest.java
    ├── service
    │   ├── UserServiceIntegrationTest.java
    │   └── ItemServiceIntegrationTest.java
    └── repository
        ├── UserRepositoryIntegrationTest.java
        └── ItemRepositoryIntegrationTest.java

4. 실무에서의 통합 테스트 구성

4.1 Spring Boot 통합 테스트 기본 구조

통합 테스트는 아래와 같은 방식으로 구성하는 것이 적합하다.

@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void testGetUsers() throws Exception {
        mockMvc.perform(get("/users"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.length()").value(3));
    }
}

4.2 @Tag로 테스트를 구분하는 것이 좋다

JUnit 5의 @Tag 어노테이션을 사용하여 테스트 유형을 구분할 수도 있다.

@Tag("integration")
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerIntegrationTest { ... }

5. 통합 테스트와 단위 테스트 실행 분리

단위 테스트와 통합 테스트를 별도로 실행하려면 빌드 도구에서 테스트 태스크를 구분하는 것이 적합하다.

Gradle 설정

Gradle에서는 테스트 태스크를 구분할 수 있는 설정이 적합하다.

tasks.test {
    include '**/unit/**'
}

task integrationTest(type: Test) {
    include '**/integration/**'
    shouldRunAfter test
}

결론

  • 추천 패키징 구조는 다음과 같다:

    • 단위 테스트: src/test/java/com.example.project/unit/
    • 통합 테스트: src/test/java/com.example.project/integration/
    • 실제 코드와 동일한 패키지 구조를 유지하는 것이 좋다.
  • 실무에서는 다음 방식을 적용하는 것이 좋다:

    • 프로젝트 복잡성에 따라 기능별 구분, 레이어별 구분, 또는 태그를 사용한 구분 방식을 선택한다.
    • Maven/Gradle 설정으로 단위 테스트와 통합 테스트 실행을 분리하여 관리한다.

이와 같은 방식으로 패키지 구조를 체계적으로 관리하면 테스트의 명확성과 효율성을 높이는 데 도움이 된다.

0개의 댓글