먼저 예제 코드에 대해 간략히 설명 드리겠습니다. (진행 중인 프로젝트를 참고한 코드입니다.)
예제 코드
🎯QueryDslConfig
@Configuration
public class QueryDslConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
QueryDsl 을 사용하기 위한 JPAQueryFactory 를 EntityManager 를 주입받아 스프링 빈으로 생성해 QueryDsl 를 활용해 동적 쿼리를 어디서든 작성할 수 있게끔 설정한 클래스 입니다.
🎯CustomHomeRepository
package com.comumu.hmj.home.repository.querydsl;
import com.comumu.hmj.home.domain.Home;
import java.util.List;
public interface CustomHomeRepository {
//검색 조건에 맞춘 동적 검색
List<Home> findByFilter();
//주소를 기반으로 찾기
List<Home> findByAddress();
Home test(Integer peopleCount);
}
해당 포스팅에서는 test() 메서드를 이용해 쿼리를 만들고 테스트 할 예정입니다.
🎯CustomHomeRepositoryImpl
package com.comumu.hmj.home.repository.querydsl;
import com.comumu.hmj.home.domain.Home;
import com.comumu.hmj.home.domain.QHome;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
@RequiredArgsConstructor
public class CustomHomeRepositoryImpl implements CustomHomeRepository {
private final JPAQueryFactory query;
private final QHome qHome = QHome.home;
@Override
public List<Home> findByFilter() {
return null;
}
@Override
public List<Home> findByAddress() {
return null;
}
@Override
public Home test(Integer peopleCount) {
Home first = query.selectFrom(qHome)
.where(qHome.peopleCount.eq(peopleCount))
.orderBy(qHome.peopleCount.desc())
.stream().findFirst()
.orElseThrow(() -> new IllegalArgumentException("에러 발생"));
return first;
}
}
test() 메서드를 오버라이드해 쿼리를 만들었습니다. Home 에 있는 peopleCount 필드를 이용해 동일한 peopleCount 값이 있다면 조회 후 반환하는 메서드 입니다.
🎯 HomeRepository
package com.comumu.hmj.home.repository;
import com.comumu.hmj.home.domain.Home;
import com.comumu.hmj.home.repository.querydsl.CustomHomeRepository;
import org.springframework.data.jpa.repository.JpaRepository;
public interface HomeRepository extends JpaRepository<Home,Long>, CustomHomeRepository {
}
JPA 와 QueryDsl 를 동시에 사용하기 위해 JpaRepository 와 CustomHomeRepository 를 상속받습니다.
QueryDsl 테스트 방법
QueryDsl 를 테스트 할때 처음에는 Mock 을 사용해 각각의 상황에 맞는 반환값들을 직접 설정해 테스트 하려했습니다. 하지만 Repository 영역은 Mock 을 이용해 직접 상황을 가정해버리면 본질적인 테스트가 힘들다 판단했고, 직접 필요한 연관관계를 주입해 테스트 코드를 구현했고 방법은 다음과 같습니다.
(1) JPAQueryFactory 를 빈으로 등록한다.
(2) QueryDsl 기능을 테스트하고 싶은 테스트 클래스에 등록한 JPAQueryFactory 를 주입한다.
(3) Repository 는 DB 와 직접적인 소통을 해야하는 영역이니 @AutoConfigureTestDatabase 애노테이션을 사용해 테스트용 DB 를 설정한다.
🎯 TestConfig
package com.comumu.hmj.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
@TestConfiguration
public class TestConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
@TestConfiguration : 애노테이션은 테스트를 할 때, 실제 애플리케이션 컨텍스트가 아닌 테스트용 configuration 을 사용할때 쓰입니다.
JPAQueryFactory 를 스프링 빈으로 등록해 주는 코드입니다.
🎯 CustomHomeRepositoryImplTest
package com.comumu.hmj.home.repository.querydsl;
import com.comumu.hmj.config.TestConfig;
import com.comumu.hmj.home.domain.Home;
import com.comumu.hmj.home.repository.HomeRepository;
import org.assertj.core.api.Assertions;
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;
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(TestConfig.class)
class CustomHomeRepositoryImplTest {
@Autowired
private HomeRepository homeRepository;
@Test
void test() {
Home home = Home.builder()
.peopleCount(5)
.build();
homeRepository.save(home);
Home test = homeRepository.test(5);
Assertions.assertThat(test.getPeopleCount()).isEqualTo(5);
}
}
@DataJpaTest : JPA 컴포넌트를 위한 테스트 애노테이션입니다. JPA 에 필요한 설정들에 대해서만 Bean 을 등록합니다.
@AutoConfigureDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) : 테스트용 DB 를 설정하는 애노테이션 입니다.
@Import(TestConfig.class) : JPAQueryFactory 빈을 주입합니다.
정리
이처럼 TestConfig 클래스를 만들어 직접 빈을 등록하는 이유는 퍼시스턴스 계층이 아니기 때문입니다. 퍼시스턴트 계층은 DB 와 연결하는 지접을 의미하는데 @DataJpaTest 를 사용하면 JPA 에 필요한 빈들을 등록하는데 이는 JPAQueryFactory 를 빈으로 등록하지 않아 직접 등록해 줘야 합니다.
'Spring > 테스트 코드' 카테고리의 다른 글
[Spring] 권한이 필요한 API 통합 테스트 설계 방법에 대해 알아보자 (0) | 2024.07.16 |
---|---|
Spring Boot 외부 라이브러리 테스트코드 작성예제 (0) | 2023.05.12 |