글 작성자: beaniejoy

QueryDSL을 공부해보면서 간단하게 프로젝트 구성해보고 QueryDSL 사용에 대한 간단한 테스트를 해보았습니다. JUnit을 이용한 QueryDSL 테스트를 진행해보았는데 테스트 진행을 위한 JUnit 환경 설정하는데에 꽤나 시간이 걸렸던 것 같습니다.

Repository를 이용한 테스트가 아닌 EntityManager를 가져와서 QueryDSL에 대한 간단한 테스트를 해보려 합니다. EntityManager를 이용한 테스트를 위해서 JUnit 설정이 살짝 달랐는데요. 이에 대한 내용을 정리해보고자 합니다.

 

📌 1. 기본적인 프로젝트 구성

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'

    // QueryDSL plugin
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
    implementation "com.querydsl:querydsl-core:${queryDslVersion}"
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"

    runtimeOnly 'mysql:mysql-connector-java'
    runtimeOnly 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

QueryDSL을 사용하기 위해서 관련 plugin을 설정했습니다. 해당 플러그인 관련해서는 관련링크를 참조하시면 될 것 같아요
https://gaemi606.tistory.com/entry/Spring-Boot-Querydsl-%EC%B6%94%EA%B0%80-Gradle-7x

 

Spring Boot | Querydsl 추가 (Gradle 7.x)

📌참고!!!! [gradle] 그레이들 Annotation processor 와 Querydsl Querydsl은 JPQL 빌더 오픈소스 프레임워크다. 일단 Querydsl 을 사용하기 위해 라이브러리를 추가해야 한다. SpringDataJPA도 추가되어 있어야..

gaemi606.tistory.com

gradle 설정이후 build를 하면 JPA Entity 기준으로 다음과 같이 QueryDSL 관려 클래스를 생성해줍니다.

build를 진행하고 나면 해당 디렉토리(build/generated/sources/annotationProcessor/java/main)에 생성이 되는 것을 확인할 수 있습니다. 

여기까지 진행됐으면 QueryDSL JUnit 테스트를 위한 기본 설정이 완료됩니다.

 

📌 2. JUnit5를 통한 기본 설정

JUnit5에서 EntityManager를 가져와서 기본적인 QueryDSL을 테스트해보고자 합니다.

@DataJpaTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class CafeQuerydslTest {
    //...
}
  • @DataJpaTest
    JPA 관련 테스트 설정만 로드합니다. EntityManager를 가져올 수 있는 TestEntityManager bean을 생성해줍니다.
  • @ActiveProfiles("test")
    yaml 설정에 test profile로 만들어둔 DB 설정내용이 있는데 해당 설정내용을 가져옵니다. 저는 인메모리 방식의 h2 DB를 가지고 테스트를 진행해보려 test profile을 지정하였습니다.
  • @AutoConfigureTestDatabase
    테스트용 DataSource를 어떤걸로 설정할 것인지를 알려주는 어노테이션입니다. 해당 어노테이션만 지정하면 Replace.ANY가 디폴트로 설정되어 Spring의 임베디드 DB를 사용하게 됩니다. 저는 위에서 test profile에 등록한 DB설정을 가지고 테스트할 것이기에 디폴트로 제공하는 DataSource를 사용하지 않을 것입니다. Replace.NONE을 명시적으로 설정함으로써 @ActiveProfiles 설정된 내용을 가지고 올 것임을 지정하면 됩니다.

 

📌 3. Test 코드 작성하기

@DataJpaTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class CafeQuerydslTest {
    @Autowired
    TestEntityManager testEntityManager;

    EntityManager em;

    @BeforeEach
    void init() {
        em = testEntityManager.getEntityManager();
    }

    @Test
    @DisplayName("cafe name 기준으로 equal 조회")
    void findByNameTest() {
        JPAQuery<Cafe> query = new JPAQuery<>(em);
        QCafe qCafe = new QCafe("c");

        List<Cafe> cafeList = query.from(qCafe)
                .where(qCafe.name.eq("test_cafe_1"))
                .fetch();

        assertEquals(cafeList.size(), 1);
    }
}

@DataJpaTest를 지정하면 TestEntityManager를 주입받을 수 있습니다. 이것을 토대로 entityManager를 꺼내서 원하는 QueryDSL 테스트를 진행할 수 있습니다.

QueryDSL 문법을 이용한 조회쿼리 작성에 대해서 추후에 정리해보는 시간을 가지는 것으로 하고 이번에는 위에 작성한 테스트 코드가 제대로 작동하는지만 확인해보겠습니다.

보기좋게 테스트를 통과하는 것을 볼 수 있습니다.

 

📌 4. SpringBootTest 연동시 테스트 FAIL 이슈

위에 작성한 테스트 코드는 단순히 EntityManager를 가져와 QueryDSL 문법을 이용해 기본적인 쿼리를 테스트해보는 내용입니다. 저는 해당 프로젝트에 QueryDSL말고 다른 테스트 코드가 존재하는데 거기서는 @SpringBootTest로 작동하는 코드입니다.

@SpringBootTest@DataJpaTest와 다르게 스프링의 등록된 모든 빈을 로드해서 테스트하는 방식으로 이루어집니다. 현재 프로젝트에는 등록된 bean이 거의 없어서 @SpringBootTest@DataJpaTest와 테스트 성능 차이가 거의 안나겠지만 방대한 양을 가진 프로젝트에서 성능에 차이가 많이 발생할 것으로 생각됩니다.

우선 그러한 사항을 제쳐두고 현재 제 개인 프로젝트에서 @SpringBootTest@DataJpaTest로 설정된 테스트 코드가 같이 존재하는데 전체 프로젝트 테스트를 진행하면 다음과 같이 @DataJpaTest 내용이 실패하는 것을 확인할 수 있습니다. 

(참고로 사진에 CafeServiceTest의 QueryDSL 기본 카페 리스트 조회 부분은 EntityManager로 테스트하는 것이 아닌 Spring Data JPA를 사용한 구현체를 가지로 테스트하는 부분이라 통과한 것입니다.)

@DataJpaTest@SpringBootTest와 같이 테스트를 진행할 수 있는지에 대해서는 여러 자료들을 찾아봤지만 아직까지 해결이 안되어 우선 다음과 같이 임시방편으로 설정하였습니다.

@Disabled
@DataJpaTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class CafeQuerydslTest {
   //...
}

이렇게 하면 @Disabled 설정된 테스트코드에 대해서만 테스트를 수행하지않고 테스트를 수행합니다. 그래서 @DataJpaTest로 설정된 테스트 코드끼리 실행을 하는 등의 방법으로 테스트를 진행하고 있습니다.
(전체 테스트 진행을 할 수 있는 방법을 알게 되면 정리해서 따로 글 작성해야겠습니다.)

 

📌 5. @SpringBootTest로만 진행하기

사실 위의 부분 FAIL 이슈를 해결하는 또하나의 방법이 있습니다. 바로 @SpringBootTest로만 테스트를 진행하는 것입니다. 저는 사실 @DataJpaTest 설정된 테스트 코드와 같이 한꺼번에 수행하도록 하고 싶었는데 이런 방법도 있다는 것만 알아두자는 차원에서 기록해두고자 합니다.

@SpringBootTest
@ActiveProfiles("test")
public class CafeRepositoryQuerydslTest {
//    @Autowired
//    TestEntityManager testEntityManager;

    @Autowired
    EntityManager em;

//    @BeforeEach
//    void init() {
//        em = testEntityManager.getEntityManager();
//    }

	//...
}

@DataJpaTest@AutoConfigureTestDatabase 내용을 걷어내고 @SpringBootTest로 설정합니다.
그러면 TestEntityManager를 주입받을 수 없게되는데 EntityManager를 직접 Autowired로 주입받으면 됩니다.
(@SpringBootTest는 Spring에 등록된 모든 빈을 로드하기 때문에 직접 주입받을 수 있는 것입니다.)

이렇게해서 전체 테스트를 진행하면 다음과 같이 깔끔하게 모든 테스트가 통과하는 것을 확인할 수 있습니다.

 

📌 6. 정리

지금까지 JUnit5 환경에서 EntityManager를 이용한 QueryDSL 기본 테스트 코드 구성해보는 내용을 정리해보았는데요.

사실 여기서 중요한 포인트가 @DataJpaTest@SpringBootTest 설정인 것 같습니다. JUnit에서 사용되는 테스트 관련 어노테이션은 쓰임새도 다 다르고 상황마다 쓰이는 어노테이션도 다르기 때문에 하나하나 면밀하게 볼 필요가 있습니다.
(Controller단, Service단, Repository단, 외부 모듈 자체 단일 테스트 등 Layer에 따라 각기 다른 테스트 설정을 해야합니다.)

아직 @DataJpaTest@SpringBootTest를 혼용해서 사용하는 방법에 대해 알아내질 못했지만 임시방편으로 전체 테스트를 수행하는 방법에 대해서도 알아보았습니다.

JUnit에 대해서 아는 것이 없어서 이쪽으로 더 공부해보고 한번 프로젝트에 적용해 봐야겠습니다.

위의 내용은 github에 커밋되어 있습니다. 해당 링크 참고하시면 될 것 같습니다!
https://github.com/beaniejoy/test-project-repository/tree/main/spring-data-jpa/src/test/java/io/beaniejoy/springdatajpa/querydsl

 

GitHub - beaniejoy/test-project-repository: 🧪 Study & Test Repository, which manages and tests various frameworks, libraries

🧪 Study & Test Repository, which manages and tests various frameworks, libraries and modules, that consists of directories named by each topic. - GitHub - beaniejoy/test-project-repository: 🧪 S...

github.com

 

틀린 내용이 많이 있을 수 있습니다. 언제나 건강한 피드백 환영합니다!~