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

Sun님의 프로필 이미지

작성한 질문수

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

EntityManager를 사용하는 Repository의 단위 테스트는 어떻게 수행하나요?

해결된 질문

작성

·

2K

3

이번 강의에서는 Service 단위 테스트를 주로 수행하셨는데, Repository나 Domain 단위 등으로 쪼개서 테스트를 수행하는 게 보다 확실하다고 말씀해주셨습니다.

그 장점으로는 1) 테스트 속도가 빠르다. 2) 보다 정확하다. 를 말씀해주셨던 걸로 기억합니다.

강의 완강 후 학습 내용을 바탕으로 작은 실습을 해보고 있는데 이와 관련된 궁금증이 있어 질문드립니다.

Repository에서 EntityManager @RequiredArgsConstructor으로 주입 받아 사용중입니다.

이 경우 Spring에서 EntityManager를 주입해주는 것이기 때문에 @SpringBootTest가 필수적인 걸까요?

만약 그렇다면 Repository와 Service단에서는 빠른 테스트를 수행하는 게 불가능하다고 생각하면 될까요? 혹은 다른 방법이 있다면 경험과 지식을 공유해주시면 감사하겠습니다.

좋은 하루 보내세요.

답변 2

5

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

안녕하세요. 썬님 좋은 질문입니다.

먼저 EntityManager를 사용하려면 스프링과 통합 테스트가 필요합니다. 그래서 @SpringBootTest가 필요합니다.

(순수 JPA를 설정할 수 있지만 배보다 배꼽이 큽니다 ㅎㅎ)

Repository는 내부에 로직이 거의 없고, 기능 대부분을 EntityManager에 의존하기 때문에, 테스트 할 때는 스프링과 통합 테스트를 많이 하게 됩니다. (사실 데이터베이스에 잘 입력이 되었는가 아닌가가 대부분 핵심 검증 내용이지요.)

그런데! 진짜 핵심은 사실 Repository가 아닙니다. 서비스에서 가장 중요한 것은 바로 핵심 비즈니스 로직입니다. 그리고 핵심 비즈니스 로직은 바로 Service에 있습니다.

그러면 여기서 고민이 되시는 부분이 바로 Service가 Repository에 의존하기 때문에 고민이 있을거에요.

여기서 바로 스프링 의존관계 주입(DI)의 힘이 발휘됩니다.

Repository를 EntityManager나 DB에 접는하는 코드를 모두 제거하고, 단순히 내가 의도한 값만 반환하도록 MockRepository라는 것으로 구현하고, 테스트 시점에 다음과 같이 코드를 진행하면 됩니다.

Service service = new Service(new MockRepository());

하지만 이렇게 구현하면 너무 불편하니 개발자를 대신해서 가짜 구현 클래스(mock)를 만들어주는 라이브러리가 바로 mockito(https://site.mockito.org/) 입니다.

실무에서는 대부분 mock 클래스를 사용할 때 이 mockito 라이브러리를 사용합니다.

(스프링 부트는 기본으로 mockito라이브러리를 포함하고 있습니다^^)

mockito 사용법으로 구글에 검색해보시면 원하시는 자료를 많이 찾으실 수 있을거에요^^

도움이 되셨길 바래요~

프로젝트 진행중에 테스트 관련되서 고민이 많았는데 좋은 내용을 찾게됬네요! 감사합니다 ㅎㅎㅎ

0

저도  궁금했던 부분인데 대신 질문해주셨네요!

처음 목 써보는거라 허접하긴 한데, 아래 같은 컨셉으로 목을 쓰는건지 궁금하네요.

ps] autowired 필드 주입 안티패턴이라고, final,requiredargsconstructor 쓰는거 핵심원리 강좌에서 애기해주셧는데, 왜 그리해야 하는지 실감나네요)


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.BDDMockito.given;

import java.util.ArrayList;
import java.util.List;
import jpabook.jpashop_v2.domain.Member;
import jpabook.jpashop_v2.repository.MemberJpaRepository;
import jpabook.jpashop_v2.service.MemberService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class MemberServiceMockTest {

// @InjectMocks
private MemberService memberService;

@Mock
private MemberJpaRepository memberRepository;

@BeforeEach
void setup() {
memberService = new MemberService(memberRepository);
}

@Test
@DisplayName("mockito 레포지토리 테스트")
void mockMemberRepositoryTest() {
//given
Member member1 = Member.builder().name("mock1").age(20).build();
List<Member> members = new ArrayList<>();
members.add(member1);

given(memberRepository.findAll()).willReturn(members);
//when
List<Member> findMembers = memberRepository.findAll();
System.out.println("findMembers = " + findMembers);

//then
assertEquals(1, findMembers.size());
assertEquals(member1.getName(), findMembers.get(0).getName());
}

@Test
@DisplayName("mockito service 테스트")
void mockMemberServiceTest() {

//given
Member member1 = Member.builder()
.name("mock유저1")
.age(20)
.build();
List<Member> members = new ArrayList<>();
members.add(member1);

given(memberRepository.findAll()).willReturn(members);

//when
List<Member> findMembers = memberService.findAll();

System.out.println("memberAll = " + findMembers);

//then
assertEquals(member1.getName(), findMembers.get(0).getName());
}


}
Sun님의 프로필 이미지

작성한 질문수

질문하기