QueryDSL JPA Test (Spring Boot 3.0) - QueryDSL 사용하기(3)공부방2023. 8. 3. 07:52
Table of Contents
728x90
728x90
셋팅
def queryDslVersion = '5.0.0'
dependencies {
//QueryDsl
// 필수
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
implementation "com.querydsl:querydsl-core:${queryDslVersion}"
// QueryDsl 쿼리 타입 생성 (QClass 생성 시 @Entity 탐색)
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
// java.lang.NoClassDefFoundError:javax/persistence/Entity 에러 방지
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
}
// QueryDsl 빌드 옵션 (선택)
// QueryDsl 디렉토리 경로
def querydslDir = "$buildDir/generated/querydsl"
// 경로 추가 >> QueryDsl 소스 코드 컴파일 시 빌드
sourceSets {
main.java.srcDirs += [ querydslDir ]
}
// 컴파일 설정(AnnotationProcessor가 생성하는 소스코드를 해당 경로로 설정)
tasks.withType(JavaCompile) {
options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir)
}
// clean실행 시 마지막 작업으로 디렉토리(QClass) 삭제 >> 충돌 방지
clean.doLast {
file(querydslDir).deleteDir()
}
위와 같은 셋팅을 사용했고, 주의할 점은 아래에 있다.
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
//implementation 'com.querydsl:querydsl-jpa'
아래처럼, 버전과 jakarta를 명시해주지 않으면 Config파일 설정 시 에러가 발생한다.
또한 Q 파일을 찾지 못해 java.lang.NoClassDefFoundException 관련 에러가 발생한다면 아래 코드를 추가하자.
annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
또한 아래의 Config 클래스를 생성하여 JPAQueryFactory를 Bean으로 등록해주었다.
필요 시 Repository에서 JPAQueryFactory를 DI하여 사용할 수 있다.
@Configuration
@RequiredArgsConstructor
public class QuerydslConfig {
private final EntityManager em;
@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em){
return new JPAQueryFactory(em);
}
}
모든 설정을 마쳤다면 Gradle - Build - Clean 후 compileJava를 수행하거나. (Gradle 빌드 도구 활용)
직접 터미널에 아래 명령어를 입력해도 된다.
./gradlew clean
./gradlew compileJava
테스트 해보기
package com.example.lolchampionsinvestment;
import com.example.lolchampionsinvestment.config.QuerydslConfig;
import com.example.lolchampionsinvestment.domain.champion.Champion;
import com.example.lolchampionsinvestment.domain.champion.ChampionRepository;
import com.example.lolchampionsinvestment.domain.champion.QChampion;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.BeforeEach;
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.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import java.time.LocalDateTime;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
@ActiveProfiles("test")
@Import(QuerydslConfig.class)
@Transactional
public class QuerydslTest {
@PersistenceContext
EntityManager em;
JPAQueryFactory jpaQueryFactory;
@BeforeEach
void init() {
jpaQueryFactory = new JPAQueryFactory(em);
Champion aatrox = createChampion("Aatrox", 1000, "아트록스", LocalDateTime.now());
Champion teemo = createChampion("Teemo", 2000, "티모", LocalDateTime.now());
Champion ahri = createChampion("Ahri", 3000, "아리", LocalDateTime.now());
em.persist(aatrox);
em.persist(teemo);
em.persist(ahri);
}
@DisplayName("Querydsl test >> 올바르게 insert되었는지 확인")
@Test
void selectBeforeInsertDataWithQuerydsl(){
//given
QChampion champion = new QChampion("champion");
//when
Champion result1 = jpaQueryFactory.select(champion)
.from(champion)
.where(champion.name.eq("Aatrox"))
.fetchOne();
Champion result2 = jpaQueryFactory.select(champion)
.from(champion)
.where(champion.name.eq("Teemo"))
.fetchOne();
Champion result3 = jpaQueryFactory.select(champion)
.from(champion)
.where(champion.name.eq("Ahri"))
.fetchOne();
//then
assertThat(result1.getName()).isEqualTo("Aatrox");
assertThat(result2.getPrice()).isEqualTo(2000);
assertThat(result3.getDescription()).isEqualTo("아리");
}
private static Champion createChampion(String name, int price, String description, LocalDateTime createDateTime) {
return Champion.builder()
.name(name)
.price(price)
.description(description)
.createDateTime(createDateTime)
.build();
}
}
테스트는 정상 수행되었다.
Insert 세 건에 대한 조회를 진행하여 모두 일치하는 것을 확인할 수 있다.
다양한 쿼리 키워드나, 연산에 대한 사용법은 정리가 잘 된 포스팅을 발견했다. 결국 API를 호출해서 API의 포맷대로 잘 사용하면 되는 것 같다.
마무리
다음 포스팅에선, 드디어 실제 토이 프로젝트에 적용될 예시 쿼리를 QueryDSL로 직접 사용해서 View까지 해보도록 하겠다.
참조
https://tecoble.techcourse.co.kr/post/2021-08-08-basic-querydsl/
관련 포스팅
728x90
300x250
@mag1c :: 꾸준히 재밌게
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!