일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 스레드 제어와 생명 주기
- 인프런
- java network
- 쓰레드
- 자료구조
- 시작하세요 도커 & 쿠버네티스
- java socket
- 자바
- 컨테이너
- Kubernetes
- 도커
- filewriter filereader
- Docker
- 동시성
- Java IO
- 도커 엔진
- 김영한
- java
- 쿠버네티스
- LIST
- 알고리즘
- 스레드
- Thread
- 자바 io 보조스트림
- container
- 자바 입출력 스트림
- 리스트
- 멀티 쓰레드
- 실전 자바 고급 1편
- Collection
- Today
- Total
쌩로그
@DataJpaTest VS @SpringBootTest (feat.QueryDSL) 본문
목차
- 포스팅 개요
- 본론
- 요약 및 참고 블로그
1. 포스팅 개요
해당 포스팅은 트러블 슈팅 포스팅이다.
요즘 부트캠프 때 진행했던 메인 프로젝트르 리팩터링 하는 중이다.
최대한 테스트 코드를 많이 짜고 있다.
일단 내가 맡았던 도메인이었던 Borrow 라는 대여 CRUD를 지금 개발 & 구현 중인데,
목록 쪽 개발중이다.
여러 건의 게시물 목록을 응답하기 위해서 QueryDSL을 사용 중이다.(나중에는 JOOQ 배우고 JOOQ로 변경해볼 예정이다.)
지금까지 트러블 슈팅 만난 배경이다.
어디서 문제를 만났는지는 본론에서 살펴보자.
2. 본론
두 개의 코드를 아래에 쓸 것이다.
근데 진짜 똑같다.
한 군데가 다르다.
근데 그 한 군데 때문에 테스트가 성공하거나, 테스트가 실패한다.
(import와 패키지는 생략한다.)
먼저 성공하는 코드다.
@SpringBootTest
class BorrowQueryRepositoryImplTest {
@Autowired
EntityManager em;
@Autowired
BorrowRepository borrowRepository;
@Autowired
BorrowQueryRepository borrowQueryRepository;
@Test
void getBorrowListTest() {
//given
Borrow dddBorrow = Borrow.createBorrow(getCreateBorrowDto(1L, "DDD", "도메인 주도 개발 대여해드립니다."));
Borrow caBorrow = Borrow.createBorrow(getCreateBorrowDto(2L, "클린 아키텍처", "클린 아키텍처 빌려드립니다."));
Borrow rmBorrow = Borrow.createBorrow(getCreateBorrowDto(3L, "Real MySql 1", "Real MySql 1 빌려드립니다."));
borrowRepository.saveAll(List.of(dddBorrow, caBorrow, rmBorrow));
//when
List<BorrowListQueryDto> borrowList = borrowQueryRepository.getBorrowList(null, null);
//then
assertThat(borrowList).hasSize(3);
assertThat(borrowList).extracting("bookTitle")
.containsExactlyInAnyOrder("DDD", "클린 아키텍처", "Real MySql 1");
}
private CreateBorrowDto getCreateBorrowDto(Long memberId, String bookTitle, String title) {
return CreateBorrowDto.builder()
.title(title)
.content("책 빌려드립니다.")
.author("에릭 에반스")
.bookTitle(bookTitle)
.publisher("한빛? 에이콘이었나..?")
.thumbnail(null)
.memberId(memberId)
.build();
}
}

테스트 성공~
다음은 실패하는 코드다.
@DataJpaTest
class BorrowQueryRepositoryImplTest {
@Autowired
EntityManager em;
@Autowired
BorrowRepository borrowRepository;
@Autowired
BorrowQueryRepository borrowQueryRepository;
@AfterEach
void afterEach() {
borrowRepository.deleteAllInBatch();
}
@Test
void getBorrowListTest() {
//given
Borrow dddBorrow = Borrow.createBorrow(getCreateBorrowDto(1L, "DDD", "도메인 주도 개발 대여해드립니다."));
Borrow caBorrow = Borrow.createBorrow(getCreateBorrowDto(2L, "클린 아키텍처", "클린 아키텍처 빌려드립니다."));
Borrow rmBorrow = Borrow.createBorrow(getCreateBorrowDto(3L, "Real MySql 1", "Real MySql 1 빌려드립니다."));
borrowRepository.saveAll(List.of(dddBorrow, caBorrow, rmBorrow));
//when
List<BorrowListQueryDto> borrowList = borrowQueryRepository.getBorrowList(null, null);
//then
assertThat(borrowList).hasSize(3);
assertThat(borrowList).extracting("bookTitle")
.containsExactlyInAnyOrder("DDD", "클린 아키텍처", "Real MySql 1");
}
private CreateBorrowDto getCreateBorrowDto(Long memberId, String bookTitle, String title) {
return CreateBorrowDto.builder()
.title(title)
.content("책 빌려드립니다.")
.author("에릭 에반스")
.bookTitle(bookTitle)
.publisher("한빛? 에이콘이었나..?")
.thumbnail(null)
.memberId(memberId)
.build();
}
}

테스트 실패~
로그를 보자.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'refactoring.bookvillage.domain.borrow.repository.query.BorrowQueryRepositoryImplTest': Unsatisfied dependency expressed through field 'borrowQueryRepository': No qualifying bean of type 'refactoring.bookvillage.domain.borrow.repository.query.BorrowQueryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
그니까 refactoring.bookvillage.domain.borrow.repository.query.BorrowQueryRepository
타입의 Bean을 찾지 못했다는 거다.
근데 분명히 나는 @Repository
애너테이션을 보란듯이 선언했다...

근데 왜 안 될까??
답은 저기 위에 작성한 코드의 클래스 레벨을 보면 된다.
포스팅 제목과 같이
@SpringBootTest
를 쓰면 성공하고,@DataJpaTest
를 쓰면 실패한다.
처음엔 "타입이 있는데 왜 없다고 나오지?" 하면서 인터페이스-구현체
로 작성한 구조를 바꿔보기도 하는데 똑같은 에러가 나왔다.
설마 했는데, @DataJpaTest
문제였다.
@DataJpaTest
는 @SpringBootTest
와는 달리 서버 실행시 필요한 모든 Bean 을 스프링 컨텍스트에 주입하는 것이 아니라, JPA에 특화된 Bean들만 주입해주고, 테스트하도록 해서 부하를 조큼 덜 일으킨다.(그래봐야 지금 규모상으로 얼마 차이 안 나지만...)
여하튼 QueryDSL을 사용하는 BorrowQueryRepository
를 Jpa의 Bean으로 인식하지 않아서 생긴 문제였다.
이미 겪은 사람이 있었다.
그래서 그 블로그를 보고 @DataJpaTest
만으로도 해당 테스트가 돌아가게끔 하기 위해 한 번 바꿔보도록 하겠다.
결론적으로 말하면 Configuration 설정을 해주면 되더라.
참고 블로그는 아래에서도 기입할 거지만, 일단 [여기]([QueryDsl] @DataJpaTest 에서 @Repository 테스트하기 — 기억의 정류장 (tistory.com))다.
일단 나는 테스트 경로의 초기 테스트 파일이 있는 경로에 configuration
이라는 패키지를 만들고 그 안에서 Config 설정을 할 클래스를 작성할 것이다.

그리고 다음과 같이 TestQueryDslConfig
라는 클래스를 작성했다.
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import refactoring.bookvillage.domain.borrow.repository.query.BorrowQueryRepository;
import refactoring.bookvillage.domain.borrow.repository.query.BorrowQueryRepositoryImpl;
@TestConfiguration
public class TestQueryDslConfig {
@PersistenceContext
private EntityManager em;
@Bean
public BorrowQueryRepository borrowQueryRepository() {
return new BorrowQueryRepositoryImpl(em);
}
}
참고 블로그는 JPAQueryFactory
도 의존성을 주입받고 있어서EntityManager
가 JPAQueryFactory
로JPAQueryFactory
가 QueryDslRepository
로 의존하는 구조지만,
내가 사용하는 BorrowQueryRepositoryImpl
클래스는 EntityManager
를 주입받고 생성자 안에서 JPAQueryFactory
를 생성하고 있기 때문에 위와 같이 작성했다.
@Repository
public class BorrowQueryRepositoryImpl implements BorrowQueryRepository {
private final JPAQueryFactory queryFactory;
public BorrowQueryRepositoryImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}
...
}
그리고 테스트 코드에 다음과 같이 Config
클래스를 import 해주면 된다.
@Import(TestQueryDslConfig.class) // Import
@DataJpaTest
class BorrowQueryRepositoryImplTest {
@Autowired
EntityManager em;
@Autowired
BorrowRepository borrowRepository;
@Autowired
BorrowQueryRepository borrowQueryRepository;
@Test
void getBorrowListTest() {
//given
Borrow dddBorrow = Borrow.createBorrow(getCreateBorrowDto(1L, "DDD", "도메인 주도 개발 대여해드립니다."));
Borrow caBorrow = Borrow.createBorrow(getCreateBorrowDto(2L, "클린 아키텍처", "클린 아키텍처 빌려드립니다."));
Borrow rmBorrow = Borrow.createBorrow(getCreateBorrowDto(3L, "Real MySql 1", "Real MySql 1 빌려드립니다."));
borrowRepository.saveAll(List.of(dddBorrow, caBorrow, rmBorrow));
//when
List<BorrowListQueryDto> borrowList = borrowQueryRepository.getBorrowList(null, null);
//then
assertThat(borrowList).hasSize(3);
assertThat(borrowList).extracting("bookTitle")
.containsExactlyInAnyOrder("DDD", "클린 아키텍처", "Real MySql 1");
}
성공~


눈이 편안하다~
3. 요약 및 참고 블로그
요약
QueryDsl 사용시 테스트 코드작성할 떄 @DataJpaTest
를 사용해서 안 되었는데,
Config를 설정하고 Import를 해주니깐 되었다.
'TroubleShooting & 고민 > BE' 카테고리의 다른 글
컨트롤러 테스트 중 만난 org.springframework.web.HttpMediaTypeNotAcceptableException (2) | 2024.10.11 |
---|---|
@RestControllerAdvice (3) | 2024.09.16 |
검색 조건을 가진 Condition클래스 @Setter 빼기 (0) | 2023.08.15 |
전체조회시 QueryDSL 사용 (3) | 2023.08.03 |
Test코드 작성시 Post를 작성한다면, Map을 사용해보자. (0) | 2023.07.24 |