Mockito
Mock
- 테스트를 위한 가짜 객체
- Mock 객체를 이용해 다른 계층과의 연결을 끊어 계층별로 테스트
Mockito
- Spring Framework 자체적으로도 지원하는 Mocking 라이브러리
Controller 슬라이스 테스트
1. postMember()
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.hamcrest.Matchers.startsWith;
import static org.mockito.BDDMockito.*;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
public class MemberControllerMockTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private Gson gson;
@MockBean
private MemberService memberService;
@MockBean
private MemberMapper mapper;
@Test
void postMemberTest() throws Exception {
MemberDto.Post post = new MemberDto.Post(
"hgd@gmail.com",
"홍길동",
"010-1111-1111");
given(mapper.memberPostToMember(Mockito.any(MemberDto.Post.class))).willReturn(new Member());
Member mockResultMember = new Member();
mockResultMember.setMemberId(1L);
given(memberService.createMember(Mockito.any(Member.class))).willReturn(mockResultMember);
String content = gson.toJson(post);
ResultActions actions =
mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);
actions
.andExpect(status().isCreated())
.andExpect(header().string("Location", is(startsWith("/v11/members/"))));
}
}
- (1) @MockBean
- Application Context에 등록된 Bean에 대한 Mockito Mock 객체를 생성하고 주입해주는 역할
- 해당 필드의 Bean에 대한 Mock 객체를 생성 후 필드에 주입
- (2) given().willReturn()
- Stubbing 메서드
- 테스트를 위해서 Mock 객체가 항상 일정한 동작을 하도록 지정하는 것
- 서비스 계층의 메서드를 호출 시 해당 메서드를 실행하지 않고 지정한 반환값을 리턴
2. patchMember()
@Test
public void patchMemberTest() throws Exception {
long memberId = 1L;
MemberDto.Patch patch = new MemberDto.Patch(memberId, "홍길동", "010-2222-2222", Member.MemberStatus.MEMBER_ACTIVE);
String content = gson.toJson(patch);
MemberDto.Response responseDto = new MemberDto.Response(
1L,
"hgd@gmail.com",
"홍길동",
"010-2222-2222",
Member.MemberStatus.MEMBER_ACTIVE,
new Stamp());
given(mapper.memberPatchToMember(Mockito.any(MemberDto.Patch.class))).willReturn(new Member());
given(memberService.updateMember(Mockito.any(Member.class))).willReturn(new Member());
given(mapper.memberToMemberResponse(Mockito.any(Member.class))).willReturn(responseDto);
ResultActions actions =
mockMvc.perform(
patch("/v11/members/{member-id}", memberId)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);
actions
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.memberId").value(patch.getMemberId()))
.andExpect(jsonPath("$.data.name").value(patch.getName()))
.andExpect(jsonPath("$.data.phone").value(patch.getPhone()))
.andExpect(jsonPath("$.data.memberStatus").value(patch.getMemberStatus().getStatus()));
}
3. getMember()
@Test
void getMemberTest() throws Exception {
Member member = new Member();
member.setMemberId(1L);
MemberDto.Response response = new MemberDto.Response(
1L,
"hgd@gmail.com",
"홍길동",
"010-1111-1111",
Member.MemberStatus.MEMBER_ACTIVE,
new Stamp()
);
given(memberService.findMember(Mockito.anyLong())).willReturn(member);
given(mapper.memberToMemberResponse(Mockito.any(Member.class))).willReturn(response);
mockMvc.perform(
get("/v11/members/1")
.accept(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.email").value(response.getEmail()))
.andExpect(jsonPath("$.data.name").value(response.getName()))
.andExpect(jsonPath("$.data.phone").value(response.getPhone()));
}
4. getMembers()
@Test
void getMembersTest() throws Exception {
Member member1 = new Member("hgd1@gmail.com", "길동1", "010-1111-1111");
member1.setMemberStatus(Member.MemberStatus.MEMBER_ACTIVE);
member1.setStamp(new Stamp());
Member member2 = new Member("hgd2@gmail.com", "길동2", "010-2222-2222");
member2.setMemberStatus(Member.MemberStatus.MEMBER_ACTIVE);
member2.setStamp(new Stamp());
Page<Member> pageMembers =
new PageImpl<>(List.of(member1, member2),
PageRequest.of(0, 10,
Sort.by("memberId").descending()), 2);
List<MemberDto.Response> responses = List.of(
new MemberDto.Response(1L,
"hgd1@gmail.com",
"길동1",
"010-1111-1111",
Member.MemberStatus.MEMBER_ACTIVE,
new Stamp()),
new MemberDto.Response(2L,
"hgd2@gmail.com",
"길동2",
"010-2222-2222",
Member.MemberStatus.MEMBER_ACTIVE,
new Stamp())
);
given(memberService.findMembers(Mockito.anyInt(), Mockito.anyInt())).willReturn(pageMembers);
given(mapper.membersToMemberResponses(Mockito.anyList())).willReturn(responses);
String page = "1";
String size = "10";
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
queryParams.add("page", page);
queryParams.add("size", size);
ResultActions actions =
mockMvc.perform(
get("/v11/members")
.params(queryParams)
.accept(MediaType.APPLICATION_JSON)
);
MvcResult result = actions
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").isArray())
.andReturn();
List list = JsonPath.parse(result.getResponse().getContentAsString()).read("$.data");
assertThat(list.size()).isEqualTo(2);
}
- 페이지네이션을 적용하여 mockMvc.perform() 내부에서 page와 size를 .params()로 넘겨줌
5. deleteMembers()
@Test
void deleteMemberTest() throws Exception {
doNothing().when(memberService).deleteMember(Mockito.anyLong());
ResultActions actions = mockMvc.perform(delete("/v11/members/1"));
actions.andExpect(status().isNoContent());
}
Service 슬라이스 테스트
@ExtendWith(MockitoExtension.class)
public class MemberServiceMockTest {
@Mock
private MemberRepository memberRepository;
@InjectMocks
private MemberService memberService;
@Test
public void createMemberTest() {
Member member = new Member(
"hgd@gmail.com", "길동", "010-1111-1111");
BDDMockito.given(memberRepository.findByEmail(Mockito.anyString()))
.willReturn(Optional.of(member));
Assertions.assertThrows(BusinessLogicException.class,
() -> memberService.createMember(member));
}
}
- (1) @ExtendWith(MockitoExtension.class)
- Spring을 사용하지 않고, Junit에서 Mockito의 기능을 사용하기 위해 @ExtendWith(MockitoExtension.class)를 추가
- (2) @Mock
- (3) @InjectMocks
- @Mock에서 생성된 필드를 @IngectMocks가 붙은 필드에 주입