인프런 커뮤니티 질문&답변

박찬호님의 프로필 이미지
박찬호

작성한 질문수

실전! Querydsl

사용자 정의 리포지토리

search Test 관련 - JPAQueryFactory와 EntityManager

작성

·

911

1

안녕하세요
강의 항상 잘 보고 있습니다.

몇가지 궁금한 점이 있어서 질문 드립니다!

public static void main(String[] args) {
		SpringApplication.run(QuerydslApplication.class, args);
	}
	@Bean
	JPAQueryFactory jpaQueryFactory(EntityManager em){
		return new JPAQueryFactory(em);
	}

이전 MemberJpaRepository에서 보여주셨던 것과 같이 시작 메소드에서 em을 주입받은 queryFactory를 Bean으로 등록하고,

private final JPAQueryFactory queryFactory;
public MemberRepositoryImpl(JPAQueryFactory queryFactory){
    this.queryFactory = queryFactory;
}

MemberRepositoryImpl에서 위와 같이 작성하였습니다.

  1. 이 상황에서, em이 주입된 queryFactory 싱글톤 빈을 받아서 MemberRepositoryImpl이 생성될 때 그 queryFactory를 주입한다고 생각하면 될까요??

이렇게 작성하였을 때, basicTest는 통과하였습니다.

하지만 searchTest에서는 result가 비어있었습니다.
그래서 처음에 생각했을 때는, 시작메소드에서 JPAQueryFactory를 빈으로 등록했지만, 여기는 Test이기 때문에 시작 메소드를 실행하지 않았고 따라서 제대로 동작하지 않았다고 생각했었습니다.

하지만 그렇다면 뭔가 컴파일 오류가 난다던지, basicTest가 불통과된다던지 했었을 텐데, 그러지 않은 것을 보니 무언가 다른 이유가 있을거라 생각합니다.

  1. 조금 난해한 질문일 수는 있지만, 위와 같은 제 생각의 흐름에서 어떤 부분이 잘못되었는지 말씀해 주실 수 있으실까요??

또한 condition에서 setTeamName을 제거했을 때는, result를 출력했을 때, member3와 member4가 나왔고 assertThat을 그에 맞게 수정하였더니 Test가 통과되었습니다.

  1. 즉, setTeamName 조건을 더했을 때, search가 제대로 동작하지 않는 것인데, 이유가 무엇인지 모르겠습니다. 아래에 전체 코드를 첨부하겠습니다.

MemberRepositoryImpl

package study.querydsl.repository;

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import study.querydsl.dto.MemberSearchCondition;
import study.querydsl.dto.MemberTeamDto;
import study.querydsl.dto.QMemberTeamDto;

import javax.persistence.EntityManager;
import java.util.List;


import static org.springframework.util.StringUtils.hasText;
import static study.querydsl.entity.QMember.member;
import static study.querydsl.entity.QTeam.team;

//MemberRepository + "Impl" 형식을 맞춰야 한다.
public class MemberRepositoryImpl implements MemberRepositoryCustom{

    private final JPAQueryFactory queryFactory;

    //시작 메소드에서 JPAQueryFactory를 스프링 빈으로 등록해둠
    //em이 주입된 queryFactory 싱글톤 빈을 받아온 것
    //MemberRepositoryImpl이 생성될 때 그 queryFactory를 주입한다.
    public MemberRepositoryImpl(JPAQueryFactory queryFactory){
        this.queryFactory = queryFactory;
    }


    @Override
    //회원명, 팀명, 나이(ageGoe, ageLoe)
    public List<MemberTeamDto> search(MemberSearchCondition condition) {
        return queryFactory
                .select(new QMemberTeamDto(
                        member.id,
                        member.username,
                        member.age,
                        team.id,
                        team.name))
                .from(member)
                .leftJoin(member.team, team)
                .where(usernameEq(condition.getUsername()),
                        teamNameEq(condition.getTeamName()),
                        ageGoe(condition.getAgeGoe()),
                        ageLoe(condition.getAgeLoe()))
                .fetch();
    }
    private BooleanExpression usernameEq(String username) {
        return hasText(username) ? member.username.eq(username) : null;
    }

    private BooleanExpression teamNameEq(String teamName) {
        return hasText(teamName) ? member.username.eq(teamName) : null;
    }

    private BooleanExpression ageGoe(Integer ageGoe) {
        return ageGoe == null ? null : member.age.goe(ageGoe);
    }

    private BooleanExpression ageLoe(Integer ageLoe) {
        return ageLoe == null ? null : member.age.loe(ageLoe);
    }
}

MemberRepositoryTest

package study.querydsl.repository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import study.querydsl.dto.MemberSearchCondition;
import study.querydsl.dto.MemberTeamDto;
import study.querydsl.entity.Member;
import study.querydsl.entity.Team;

import javax.persistence.EntityManager;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
class MemberRepositoryTest {
    @Autowired
    EntityManager em;
    @Autowired
    MemberRepository memberRepository;

    @Test
    public void basicTest() {
        Member member = new Member("member1", 10);
        memberRepository.save(member);
        Member findMember = memberRepository.findById(member.getId()).get();
        assertThat(findMember).isEqualTo(member);
        List<Member> result1 = memberRepository.findAll();
        assertThat(result1).containsExactly(member);
        List<Member> result2 = memberRepository.findByUsername("member1");
        assertThat(result2).containsExactly(member);
    }

    @Test
    public void searchTest() {
        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);
        Member member1 = new Member("member1", 10, teamA);
        Member member2 = new Member("member2", 20, teamA);
        Member member3 = new Member("member3", 30, teamB);
        Member member4 = new Member("member4", 40, teamB);
        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);
        MemberSearchCondition condition = new MemberSearchCondition();
        condition.setAgeGoe(35);
        condition.setAgeLoe(40);
        condition.setTeamName("teamB");
        List<Member> all = memberRepository.findAll();
        List<MemberTeamDto> result = memberRepository.search(condition);
        System.out.println("all = " + all);
        System.out.println("result = " + result);
        assertThat(result).extracting("username").containsExactly("member4");
    }

}

이때 다음과 같이 변경하면 테스트가 통과됩니다.

    @Test
    public void searchTest() {
        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);
        Member member1 = new Member("member1", 10, teamA);
        Member member2 = new Member("member2", 20, teamA);
        Member member3 = new Member("member3", 30, teamB);
        Member member4 = new Member("member4", 40, teamB);
        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);
        MemberSearchCondition condition = new MemberSearchCondition();
        condition.setAgeGoe(30);
        condition.setAgeLoe(40);
//        condition.setTeamName("teamB");
        List<Member> all = memberRepository.findAll();
        List<MemberTeamDto> result = memberRepository.search(condition);
        System.out.println("all = " + all);
        System.out.println("result = " + result);
        assertThat(result).extracting("username").containsExactly("member3", "member4");
    }

답변 1

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 박찬호님

먼저 JPAQueryFactory와 EntityManager 관련해서는 아무런 문제가 없어 보입니다.

문제는 다음 코드입니다.

    private BooleanExpression teamNameEq(String teamName) {
        return hasText(teamName) ? member.username.eq(teamName) : null;
    }

코드를 잘 보시면 teanName인데, 비교 부분은 member.username으로 진행하고 있습니다.

감사합니다.

박찬호님의 프로필 이미지
박찬호

작성한 질문수

질문하기