Spring Data JPA 단위 테스트

JunitSpring Boot단위 테스트
avatar
2025.04.25
·
5 min read

이번 글에서는 Repository 계층의 단위 테스트를 어떻게 작성하는지에 대해 학습한 내용을 정리하고자 합니다.

현재 상황

  • Spring Boot : 3.0.6

  • Java : JDK17

  • MySQL 8.0.33

  • QueryDSL 사용

  • JUnit : JUnit5

  • 테스트 DB : in-memory DB(H2)

테스트 환경 설정

application-test.yml 작성

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL
    username: sa
    password:

  jpa:
    hibernate:
      ddl-auto: create-drop
      globally_quoted_identifiers: true
      format_sql: true
    show-sql: true
    generate-ddl: true
    database: h2
    properties:
      hibernate.dialect: org.hibernate.dialect.MySQL8Dialect

  h2:
    console:
      enabled: true

설정 설명

  • url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL

    • mem:test: 인메모리 DB로 생성됨 (테스트 종료 시 삭제)

    • DB_CLOSE_DELAY=-1: 연결이 끊겨도 DB 유지

    • DATABASE_TO_UPPER=false: 컬럼명 등에서 대문자 자동 변환 방지

    • MODE=MySQL: H2 데이터베이스가 MySQL 문법을 따르도록 설정

  • hibernate.dialect: Hibernate가 SQL을 생성할 때 MySQL Dialect를 사용하도록 설정

  • ddl-auto: create-drop: 테스트 시작 시 테이블을 생성하고 종료 시 제거

  • globally_quoted_identifiers: 모든 식별자(테이블, 컬럼 등)를 백틱(`)으로 감싸도록 설정하여 예약어 충돌 방지 및 대소문자 구분 명확히 함

TestConfig 작성

QueryDSL 기반 Repository 테스트 시 JPAQueryFactory가 필요합니다. 테스트 환경에서는 Spring Boot가 이를 자동으로 등록해주지 않기 때문에, 수동으로 Bean 등록이 필요합니다.
👉 작성할 Repository가 QueryDSL를 사용하지 않아도, 현재 프로젝트에서 QueryDSL를 사용 중이므로 설정을 추가해주어야 합니다.

@TestConfiguration
@EnableJpaAuditing
public class TestConfig {

    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }
}

테스트 코드 작성

테스트 클래스 어노테이션

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(TestConfig.class)
  • @DataJpaTest: JPA 관련 Bean만 로딩하여 테스트 속도와 안정성을 확보합니다.

  • @AutoConfigureTestDatabase: 테스트에서 임베디드 DB(H2)를 자동 교체하지 않도록 설정합니다.

  • @Import(TestConfig.class): 필요한 설정들을 별도로 주입합니다.

Cart 조회 성공 테스트

@Test
@DisplayName("Customer로 Cart 조회 성공")
void find_cart_by_customer_success() {
    // given
    Customer customer = CustomerFixture.createCustomer();
    customerRepository.save(customer);

    Cart cart = Cart.createCart(customer);
    cartRepository.save(cart);

    // when
    Optional<Cart> result = cartRepository.findByCustomer(customer);

    // then
    assertThat(result).isPresent();
    assertThat(result.get().getCustomer()).isEqualTo(customer);
}
  • CustomerFixture.createCustomer()를 통해 테스트 고객을 생성합니다.

  • 실제 DB에 저장된 고객을 기반으로 Cart를 생성한 후, 저장합니다.

  • findByCustomer로 조회했을 때 Cart가 반환되는지 확인합니다.

  • 연관된 Customer 정보까지 정확히 일치하는지도 검증합니다.

Cart 조회 실패 테스트

@Test
@DisplayName("Customer로 Cart 조회 실패 - 존재하지 않음")
void find_cart_by_customer_fail_not_found() {
    // given
    Customer customer = CustomerFixture.createCustomer();

    // when
    Optional<Cart> result = cartRepository.findByCustomer(customer);

    // then
    assertThat(result).isEmpty();
}
  • 저장되지 않은 Customer로 Cart를 조회했을 때 결과가 비어 있는지 확인합니다.

전체 테스트 코드

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import store.myproject.onlineshop.domain.cart.Cart;
import store.myproject.onlineshop.domain.customer.Customer;
import store.myproject.onlineshop.fixture.CustomerFixture;
import store.myproject.onlineshop.global.config.TestConfig;
import store.myproject.onlineshop.repository.customer.CustomerRepository;

import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(TestConfig.class)
class CartRepositoryTest {

    @Autowired
    CartRepository cartRepository;

    @Autowired
    CustomerRepository customerRepository;

    @Test
    @DisplayName("Customer로 Cart 조회 성공")
    void find_cart_by_customer_success() {
        // given
        Customer customer = CustomerFixture.createCustomer();
        customerRepository.save(customer);

        Cart cart = Cart.createCart(customer);
        cartRepository.save(cart);

        // when
        Optional<Cart> result = cartRepository.findByCustomer(customer);

        // then
        assertThat(result).isPresent();
        assertThat(result.get().getCustomer()).isEqualTo(customer);
    }

    @Test
    @DisplayName("Customer로 Cart 조회 실패 - 존재하지 않음")
    void find_cart_by_customer_fail_not_found() {
        // given
        Customer customer = CustomerFixture.createCustomer();

        // when
        Optional<Cart> result = cartRepository.findByCustomer(customer);

        // then
        assertThat(result).isEmpty();
    }
}

Reference
- https://0soo.tistory.com/40
- https://0soo.tistory.com/41
- https://jyami.tistory.com/124







- 컬렉션 아티클