테스트 구조 및 전략 - KimGyuBek/Threadly GitHub Wiki

개요

Thradly 프로젝트의 테스트는 실제 인프라 환경을 통합하여 Mocking을 최소화한 구조로 설계되었다.

모든 테스트는 JUnit 5, Spring Boot Test 기반으로 단위 -> 통합 -> 시나리오 계층으로 구성된다.


테스트 구조

  • 단위 테스트: 순수 도메인 로직 유틸 검증
  • 통합 테스트: 레파지토리, Redis, Kafka 등 실제 인프라 연동한 통합 테스트
  • API 시나리오 통합 테스트: 실제 요청 단위의 시나리오 기반 통합 테스트

테스트 환경

프레임 워크

JUnit 5, Mockito, AssertJ

프로필

test


API 통합 테스트

app-api 모듈의 테스트는 단순히 컨트롤러 한두 개를 호출해 보는 수준이 아니라,

다양한 시나리오에서

  • 실제 요청 및 응답 흐름
  • 인증 / 인가 필터
  • 예외 처리
  • 전역 응답 포맷
  • 도메인 서비스 + 어댑터 흐름

까지 한 번에 검증하는 실질적인 E2E 성경의 테스트를 목표로 구현했다.


테스트 목적

  • 실제 API 요청이 서비스 로직과 DB를 거쳐 정상적으로 동작하는지 검증
  • JPA 매핑, 트랜잭션 경계, 인증 인가 등을 실제 환경 수준의 동작 확인

테스트 범위

  • Post, User, Follow 등 주요 도메인 전체 API 검증
  • Json Fixture 로드 방식을 활용하여 시나리오별 일관된 환경에서 테스트 수행

API 통합 테스트 목록

목록 조회

장점

  • 높은 신뢰성: 단위 테스트로 잡기 어려운 통합 오류(JPA 매핑, 트랜잭션 등)까지 검증 가능하다.
  • 유지 보수 용이: 내부 코드 변경에도 API 유지되면 테스트 수정이 불필요하다
  • 높은 테스트 커버리지 확보: Jacoco를 이용한 테스트 커버리지 측정에서 app-api 모듈 기준 약 89% 커버리지 달성
  • 실제 시나리오 기반 검증: 실제 사용자 요청 흐름 시나리오를 기반으로 테스트를 실행한다.

테스트 클래스 구조

// GetFollowStatsApiTest.java
@TestClassOrder(ClassOrderer.OrderAnnotation.class)
@DisplayName("사용자 팔로워, 팔로잉 수 조회 API 테스트") // 테스트 대상 API 설명
public class GetFollowStatsApiTest extends BaseFollowApiTest {

  // 팔로우 통계 테스트용 메인 사용자
  public static final String MAIN_USER_ID = "main_user";
//  테스트 상수 ...

//  테스트 케이스 목록
  /*
   * 1. 자신에 대해서 요청 시 응답 검증
   * 2. ...
   * */

  @Order(1)
  @Nested
  @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
  @DisplayName("성공")
  class success {
//    성공 케이스

    /*[Case #1] 자신의 팔로워, 팔로잉 수 조회 요청 시 응답 검증*/
    @Order(1) // 테스트 메서드 실행 순서
    @DisplayName("1. 자신의 팔로워, 팔로잉 수 조회 요청 응답 검증") // 테스트 메서드 설명
    @Test
    public void getUserFollowStats_shouldSuccess_01() throws Exception {
      //given
      //when
      //then
    }
  }

  @Order(2)
  @Nested
  @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
  @DisplayName("실패")
  class fail {
//    실패 케이스
  }
}

예시

특정 사용자의 팔로우 정보(팔로잉,팔로워 수)를 조회하는 API 테스트

// GetFollwStatsApiTest.java
/*[Case #1] 자신의 팔로워, 팔로잉 수 조회 요청 시 응답 검증*/
@Order(1)
@DisplayName("1. 자신의 팔로워, 팔로잉 수 조회 요청 응답 검증")
@Test
public void getUserFollowStats_shouldSuccess_01() throws Exception {
  //given
  // 테스트 데이터 삽입
  userFollowFixtureLoader.load(
      "/users/follow/follow-stats/users.json",
      "/users/follow/follow-stats/follows.json"
  );

  String accessToken = getAccessToken(MAIN_USER_EMAIL); // 로그인 처리

  //when
  // userId에 해당하는 사용자의 팔로우 상태 조회 요청(테스트 할 API 요청)
  CommonResponse<GetUserFollowStatsApiResponse> getUserFollowStatsResponse = sendGetUserFollowStatsRequest(
      accessToken, MAIN_USER_ID, status().isOk()
  );

  //then
  // 응답 검증
  assertThat(getUserFollowStatsResponse.getData().followerCount()).isEqualTo(
      EXPECTED_FOLLOWER_COUNT);
  assertThat(getUserFollowStatsResponse.getData().followingCount()).isEqualTo(
      EXPECTED_FOLLOWING_COUNT);
}

테스트 특징

1. Jacoco 커버리지 레포트

테스트 신뢰도를 측정하기 위해서 Jacoco를 사용하여 테스트 커버리지를 측정한다.

상세 문서: Jacoco를 이용한 테스트 커버리지 측정


2. Json Fixture 기반의 테스트 데이터

API 통합 테스트는 실제 DB 데이터를 직접 사용하지 않고 시나리오별로 정의된 Json Fixture 파일을 로드해서 테스트를 수행한다.

이를 통해서 일관된 테스트 환경과 높은 안정성을 유지하며, 각 테스트에서 필요한 데이터만 선택적으로 로드하여 테스트 가능

상세 문서: Fixture 기반 테스트 데이터 전략


3. Nested 구조의 테스트 클래스

@Nested를 이용해 성공/실패를 분리해서 하나의 테스트 클래스 안에서도 성공과 실패를 명확하게 구분할 수 있어서 가독성과 유지보수성이 향상된다.

예시

nested_test_list

4. CI 기반 자동 테스트 / 커버리지 검증

Github Actions CI 파이프라인에서 모든 테스트가 자동으로 실행하며, PR 단계에서 바로 테스트 결과를 확인할 수 있도록 구성했다.

또한 Jacoco 테스트 커버리지는 CI 수행 후 JobSummary에 자동 출력되며, 각 모듈별 커버리지 상태를 즉시 파악할 수 있어 품질 관리가 한층 수월하다.

상세 문서: CI 파이프라인 구축


관련 문서

⚠️ **GitHub.com Fallback** ⚠️