Mockito를 통한 슬라이스 테스트

jungseo·2023년 7월 4일
0

Spring

목록 보기
16/23
post-thumbnail

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 // (1)
    private MemberService memberService;

    @MockBean
    private MemberMapper mapper;

    @Test
    void postMemberTest() throws Exception {
//        given
        MemberDto.Post post = new MemberDto.Post(
                "hgd@gmail.com",
                "홍길동",
                "010-1111-1111");
                
//        (2)
        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);

//        when
        ResultActions actions =
                mockMvc.perform(
                        post("/v11/members")
                                .accept(MediaType.APPLICATION_JSON)
                                .contentType(MediaType.APPLICATION_JSON)
                                .content(content)
                );

//        then
        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 {
//        given
        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());

//        willReturn()이 최소한 null은 아니어야 한다
        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);

//        when
        ResultActions actions =
                mockMvc.perform(
                        patch("/v11/members/{member-id}", memberId)
                                .accept(MediaType.APPLICATION_JSON)
                                .contentType(MediaType.APPLICATION_JSON)
                                .content(content)
                );

//        then
        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 {
//        given
        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);

//        when / then
        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) // (1)
public class MemberServiceMockTest {

    @Mock // (2)
    private MemberRepository memberRepository;

    @InjectMocks // (3)
    private MemberService memberService;

    @Test
    public void createMemberTest() {
//        given
        Member member = new Member(
                "hgd@gmail.com", "길동", "010-1111-1111");

        BDDMockito.given(memberRepository.findByEmail(Mockito.anyString()))
                .willReturn(Optional.of(member));

//        when / then
        Assertions.assertThrows(BusinessLogicException.class,
                () -> memberService.createMember(member));
    }
}
  • (1) @ExtendWith(MockitoExtension.class)
    • Spring을 사용하지 않고, Junit에서 Mockito의 기능을 사용하기 위해 @ExtendWith(MockitoExtension.class)를 추가
  • (2) @Mock
    • 해당 필드의 객체를 Mock 객체로 생성
  • (3) @InjectMocks
    • @Mock에서 생성된 필드를 @IngectMocks가 붙은 필드에 주입

0개의 댓글