📌 서론
QueryRepository로 커스텀 레파지토리를 생성하고 @DataJpaTest로 테스트를 진행하려고 보니까 해당 Repository의 빈을 찾아오지 못하는 이슈가 발생했다.
이 이슈를 해결하면서 놓쳤던 부분을 다시한번 정리해보려고 한다.
QueryDLS란?
QueryDSL은 Java 어플리케이션에서 타입 안전성을 보장하는 동시에 복잡한 쿼리를 간결하게 작성할 수 있게 해주는 프레임워크다.
특히, 스프링 부트와 함께 사용할 때, 데이터 접근 로직을 구현하는 방법에는 크게 두 가지 접근 방식이 있다: 기존의 custom interface 방식과 단독 빈으로 등록하는 QueryRepository 방식이다. 이 두 방식은 각각의 장단점을 가지며, 사용하는 컨텍스트에 따라 선택이 달라질 수 있다. 이번 글에서는 이 두 구현 방식의 차이점과 각각의 테스트 방법에 대해 알아보자.
1. 일반적인 Custom Interface 방식
이 방식에서는 QueryDSL을 사용하는 메서드들을 별도의 custom interface로 정의하고, 이를 구현하는 구현체(Impl)에서 실제 QueryDSL 로직을 작성한다. 이 구현체는 Spring Data JPA의 Repository 인터페이스에 의해 자동으로 스캔되고 빈으로 등록되며 @DataJpaTest 어노테이션을 사용하는 테스트에서도 잘 작동한다.
- 장점: 데이터 접근 계층과 비즈니스 로직 계층을 명확하게 분리할 수 있다. 또한, Repository 인터페이스의 확장성을 유지하면서 QueryDSL 기능을 추가할 수 있다.
- 단점: 추가적인 인터페이스와 구현 클래스를 만들어야 하므로, 클래스 구조가 복잡해질 수 있다.
2. QueryRepository 단독 빈 등록 방식
이 접근 방식에서는 custom interface를 정의하지 않고, 직접 구현한 QueryRepository 클래스를 스프링 빈으로 등록하여 사용한다. 이 클래스 내에서 직접 QueryDSL 로직을 작성하고, @Repository 어노테이션을 사용하여 스프링 빈으로 등록한다. 이 경우, 기존 Repository 인터페이스에 종속되지 않으며, 더 유연한 구조를 가질 수 있다.
@RequiredArgsConstructor
@Repository
public class SampleQueryRepository {
private final JPAQueryFactory jpaQueryFactory;
// 필요한 로직 작성
}
- 장점: 별도의 custom interface 없이 바로 사용할 수 있어 구조가 간결해진다. 필요한 QueryDSL 기능을 직접 구현한 클래스 내에서 자유롭게 확장할 수 있다.
- 단점: @DataJpaTest를 사용할 때, 스프링 데이터 JPA의 리포지토리 스캐닝과정에서 이 빈을 자동으로 등록하지 않아, 테스트 설정에 추가적인 작업이 필요할 수 있다. 또한, Repository 인터페이스와의 직접적인 연결이 없으므로, 일부 설계 상의 일관성이 떨어질 수 있다.
이제 각각의 repository를 테스트할때 차이점이 있어서 이 부분에도 정리해보려고 한다.
자주 사용되는 @DataJpaTest와 @SpringBootTest 어노테이션은 스프링 부트에서 제공하는 테스트 유틸리티로, 둘 다 테스트 시에 활용되지만 사용 목적과 환경 설정이 다르다.
@DataJpaTest
- @DataJpaTest는 JPA 관련 설정만 로드하여 JPA 테스트에 최적화된 환경을 제공한다.
- 주로 리포지토리 계층의 통합 테스트에 사용된다.
- 이 어노테이션은 자동으로 H2 같은 인메모리 데이터베이스를 구성하고, @Entity 클래스들과 Repository 인터페이스만 스캔하여 빈으로 등록한다.
- 따라서 JPAQueryFactory 같은 JPA 외의 컴포넌트나 사용자 정의 빈(QueryRepository와 같은)은 자동으로 스캔되어 빈으로 등록되지 않는다.
@SpringBootTest
- @SpringBootTest는 스프링 부트 어플리케이션의 전체 컨텍스트를 로드하여, 보다 복합적인 통합 테스트를 위해 사용된다.
- 전체 스프링 어플리케이션을 테스트하기 원할 때 사용되며, 모든 빈을 스캔하여 등록한다.
- QueryRepository와 같이 사용자 정의 빈도 스프링 컨텍스트에 포함되어 관리된다.
- 더 많은 리소스를 사용하고, 더 긴 부팅 시간이 필요하지만, 애플리케이션을 실행할 때와 동일한 환경에서 테스트를 진행할 수 있다는 장점이 있다.
기존의 커스텀 인터페이스와 구현체(Impl) 방식에서 Querydsl을 사용하는 경우와 직접 구현한 QueryRepository 클래스를 사용하는 방식은 각각의 구조와 테스트 접근 방법에서 명확한 차이점을 가지고 있다.
QueryDSL 구현 방식에 따른 테스트 어노테이션 차이점
Custom Interface 방식
이 방식은 Spring Data JPA와 긴밀하게 통합되므로, @DataJpaTest 어노테이션을 사용하여 리포지토리 계층의 테스트를 진행할 때, custom interface 및 그 구현체가 자동으로 스캔되어 빈으로 등록된다.
QueryRepository 단독 빈 방식
@Repository로 등록된 QueryRepository는 @DataJpaTest 어노테이션만으로는 스프링 테스트 컨텍스트에 포함되지 않는다. 이는 @DataJpaTest가 주로 JPA 리포지토리에 대한 테스트를 목적으로 하며, 이 경우 @Import 어노테이션을 사용하거나, @SpringBootTest 어노테이션으로 전환하여 전체 스프링 컨텍스트를 로드하는 방식으로 해결할 수 있다.
QueryRepository를 테스트하려면 몇 가지 방법이 있다:
- @SpringBootTest를 사용하여 전체 스프링 컨텍스트를 로드한다. 이 방법은 가장 간단하지만 테스트 실행 시간이 길어질 수 있다.
- @DataJpaTest에 @Import(SampleQueryRepository.class)를 추가하여 사용자 정의 빈을 수동으로 등록한다. 이 방법은 필요한 빈만 로드하여 리소스 사용을 최적화할 수 있다.
@DataJpaTest
@Import(SampleQueryRepository.class) // SampleQueryRepository를 수동으로 등록
public class SampleQueryRepositoryTest {
// 테스트 코드
}
'Spring > Spring Data JPA' 카테고리의 다른 글
JPA를 사용해 페이징 처리하는 두 가지 방법, Slice와 Page (0) | 2024.04.02 |
---|---|
JPA에서 Entity 복합키 관리 (@Embeddable, @EmbeddedId) (0) | 2024.04.01 |
QueryDSL 사용 시 자동 업데이트 되지 않는 JPA Auditing 수정 날짜 문제 해결 방법 (1) | 2024.02.01 |
JPA와 Spring Data JPA의 차이 (1) | 2024.01.02 |
JPA N+1 문제 해결하기 (fetch join, entityGraph, batch size) (5) | 2023.12.28 |