inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

호돌맨의 요절복통 개발쇼 (SpringBoot, Vue.JS, AWS)

postService 목록 조회 단위 테스트

559

Heechul Lee

작성한 질문수 1

0

 

안녕하세요. 호돌맨님.

postService에서 목록 조회하는 단위테스트에 대해서 질문이 있습니다.

 

먼저 목록 조회 코드부터 보여드리면

postService.findPosts 는 postQueryRepository에 구현체로 만들었습니다.

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PostService {

    public static final String ENTITY_NAME = "post";

    private final PostQueryRepository postQueryRepository;
    private final PostRepository postRepository;

    /**
     * Post 목록 조회
     */
    public Page<Post> findPosts(PostSearchCondition condition, Pageable pageable) {
        return postQueryRepository.findPosts(condition, pageable);
    }
}
@Repository
public class PostQueryRepository {

    private final JPAQueryFactory queryFactory;

    public PostQueryRepository(EntityManager em) {
        this.queryFactory = new JPAQueryFactory(em);
    }

    /**
     * Post 목록 조회
     */
    public Page<Post> findPosts(PostSearchCondition condition, Pageable pageable) {

        List<Post> content = getPostList(condition, pageable);

        JPAQuery<Long> count = getPostListCount(condition);

        return PageableExecutionUtils.getPage(content, pageable, count::fetchOne);
    }

    /**
     * Post 목록
     */
    private List<Post> getPostList(PostSearchCondition condition, Pageable pageable) {
        return queryFactory
                .select(post)
                .from(post)
                .where(
                        searchCondition(condition.getSearchCondition(), condition.getSearchKeyword())
                )
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .orderBy(post.id.desc())
                .fetch();
    }

    /**
     * Post 목록 카운트
     */
    private JPAQuery<Long> getPostListCount(PostSearchCondition condition) {
        return queryFactory
                .select(post.count())
                .from(post)
                .where(
                        searchCondition(condition.getSearchCondition(), condition.getSearchKeyword())
                );
    }

    /**
     * where searchCondition LIKE '%searchKeyword%'
     */
    private BooleanExpression searchCondition(SearchCondition searchCondition, String searchKeyword) {
        if (searchCondition == null || !hasText(searchKeyword)) {
            return null;
        }

        if (SearchCondition.TITLE.equals(searchCondition)) {
            return post.title.contains(searchKeyword);
        } else if (SearchCondition.CONTENT.equals(searchCondition)) {
            return post.content.contains(searchKeyword);
        } else {
            return null;
        }
    }
}

 

다음은 테스트 코드입니다.

@ExtendWith(MockitoExtension.class)
class PostServiceTest {

    //CREATE_POST
    public static final String POST_TITLE = "post_title";
    public static final String POST_CONTENT = "post_content";

    //UPDATE_POST
    public static final String UPDATE_TITLE = "update_title";
    public static final String UPDATE_CONTENT = "update_content";

    //ERROR_MESSAGE
    public static final String ENTITY_NAME = "post";
    public static final Long NOT_FOUND_ID = 1L;
    public static final String HAS_MESSAGE_STARTING_WITH = "존재하지 않는 ";
    public static final String HAS_MESSAGE_ENDING_WITH = "id = ";


    @InjectMocks PostService postService;

    @Mock PostQueryRepository postQueryRepository;

    @Mock PostRepository postRepository;

    private Post getPost(String title, String content) {
        return Post.createPostBuilder()
                .title(title)
                .content(content)
                .build();
    }

    @Test
    @DisplayName("post 목록 조회")
    void findPosts() {
        //given
        List<Post> posts = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            posts.add(getPost(POST_TITLE + i, POST_CONTENT));
        }

        //검색 안먹힘
        PostSearchCondition condition = new PostSearchCondition();
        condition.setSearchCondition(SearchCondition.TITLE);
        condition.setSearchKeyword("0");
        PageRequest pageRequest = PageRequest.of(0, 10);
        given(postQueryRepository.findPosts(condition, pageRequest)).willReturn(new PageImpl<>(posts));

        //when
        Page<Post> contents = postService.findPosts(condition, pageRequest);

        //then
        assertThat(contents.getTotalElements()).isEqualTo(3);
        assertThat(contents.getContent().size()).isEqualTo(3);
    }
}

 

여기서 findPosts 단위 테스트를 진행하려고 하는데요.

목록을 30개를 만들고 검색조건과 페이지 정보를 파라미터로 넘겨서 검색이 된 결과가 나올것이라고 예상했지만 검색조건은 먹히지 않고 30개의 목록만 리턴이 됩니다.

 

전 검색 조건대로 "0"들어간 title만 검색이되어서

contents.getTotalElements() == 3, contents.getcontent().size() == 3 으로 예상을 했는데

contents.getTotalElements() == 30, contents.getcontent().size() == 30 로 결과가 나와 테스트에 실패하게됩니다.

 

구글링으로 mockito, page, test, querydsl, parameter 등 다양하게 검색 해봤는데 원하는 결과를 얻기 못해 질문 한번 드려봅니다.

 

혹시나 제가 잘못된 방향으로 테스트를 진행하고 있는건지 혹은 다른 방법이 있을지 궁금합니다!

깃저장소도 같이 공유드립니다.

https://github.com/heechul90/heech-heechlog-server

 

 

JPA aws spring-boot Spring Security vuejs

답변 1

0

호돌맨

안녕하세요. 호돌맨입니다.

given(postQueryRepository.findPosts(condition, pageRequest)).willReturn(new PageImpl<>(posts));

위 코드에서 postQueryRepository.findPosts를 할 경우 posts(30개)를 반환하도록 설정 하셨기 3개가 나올 수 없습니다.

그치만.. 코드쨩.. 분명 PostSearchCondition으로 필터링 했는걸?

postQueryRepositorys는 Mock 상태입니다. Mock은 실제로 findPosts 코드를 실행하지 않습니다.
확인 해보시려면 PostQueryRepository.java안에 findPosts 첫 번째 라인에 breakpoint를 찍으신 뒤 debug 모드로 테스트를 실행하시면 breakpoint가 걸리지 않는 걸 확인해보실 수 있습니다.

QueryDSL 테스트시 @DataJpaTest검색 해보시는걸 추천드립니다.

감사합니다.

Deprecated 관련 사항들

0

128

2

깃헙 collaboator 초대 관련

0

104

1

강의 듣다가 도커 이미지 생성시 각각도 가능하나 그렇게 사용하는데가 많은지 모르겠다라는 말을 듣고 남김니다

0

171

2

logout 후에 login 페이지 이동은 어디서 시켜주는건가요?

0

243

1

다중 데이터를 삭제 할 때

0

291

2

querydsl Q class 이슈

0

433

2

Windows WSL Vue 설정

2

255

1

Dip, @transactional

0

199

1

[vite] http proxy error: /auth/login

0

1067

2

로그인 하고 나서 GET요청으로 메인페이지 요청

0

246

2

GitHub Collaborator 초대 관련

0

283

2

Window에서 Vue.js 설정

0

334

2

collaboator로 초대받을 수 있을까요??

0

298

2

SecurityMockContext 로부터 유저 정보를 가져오기

0

276

1

섹션9 프론트의 코드를 보고싶습니다,,,

0

427

1

Spring Security - defaultSuccessUrl 질문

0

639

1

강의 화면이 나오지 않습니다. 음성과 자막만 나와요

0

313

1

JPAQueryFactory(em)의 객체 생성자 오류에 대해서 질문이 있습니다ㅜㅜ

0

702

2

ExceptionHandler가 AccessDeniedHandler(Http403Handler)를 먹어버리는 현상

0

1184

2

섹션10 언제 나오나요?

0

489

1

CommentService에서 Repository를 호출하지 않는데도

0

346

1

Editor....를 활용한 패턴에 질문있습니다.

0

500

1

섹션9 vue

0

460

2

Post에 edit 메서드 삼항연산자 질문

0

480

2