[Section3] Spring MVC - Testing 3

2023. 7. 2. 16:50

🧑🏻‍💻 TIL(Today I Learned)


✔️ Mockito, TDD

 

💡 Mock이란?

➡️ 테스트 세계에서의  Mock이란 가짜 객체를 의미, 단위 테스트나 슬라이스 테스트 등에 Mock 객체를 사용하는 것을 Mocking이라고 함

Mock-up(목업)
: 실제 제품이 나오기 전에 내부적으로 사용하기 위한 모형(가짜) 제품 의미

 

🔎 테스트에서 Mock 객체를 사용하는 이유 

  • Mock 객체를 사용하지 않은 슬라이스 테스트 프로세스
    • MemberControllerTest의 postMemberTest() 실행 시 테스트 실행 흐름은 아래와 같음

  • 하지만 MemberControllerTest 클래스는 완전한 슬라이스 테스트라고 보기 어려움 
    → postMember() 핸들러 메서드 쪽만 테스트 해야 하는데 서비스 계층을 거쳐서 데이터 액세스 계층, 데이터베이스까지 동작 흐름이 끝까지 이어졌다가 되돌아오기때문에 슬라이스 테스트보다는 통합 테스트에 더 가까움
  • 즉, 슬라이스 테스트는 해당 계층 영역에 대한 테스트에 집중해야하는 것인데 Controller 에만 집중하는 것이 아니라 불필요한 전 계층을 다 거쳐야 되기 때문에 성능 면에서 테스트 관심 영역 면에서 슬라이스 테스트의 주목적에 맞지 않음

 

  • Mock 객체를 사용한 슬라이스 테스트 프로세스

  • Mock 객체를 이용함으로써 다른 계층과 단절되어 불필요한 과정을 줄이는 것을 확인할 수 있음 

 

 

💡 Mockito

➡️ Mock 객체를 사용하기 위해 가장 많이 사용되고 Spring Framework 자체적으로도 지원하고 있는 Mocking 라이브러리

➡️ Mock 객체를 생성하고 해당 Mock 객체가 진짜처럼 동작하게 하는 역할을 담당

 

✔️ Mockito 적용하기

@SpringBootTest
@AutoConfigureMockMvc
class MemberControllerMockTest {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private Gson gson;

    // (1)
    @MockBean
    private MemberService memberService;

    // (2)
    @Autowired
    private MemberMapper mapper;

    @Test
    void postMemberTest() throws Exception {
        // given
        MemberDto.Post post = new MemberDto.Post("hgd@gmail.com",
                                                        "홍길동",
                                                    "010-1234-5678");
				
        Member member = mapper.memberPostToMember(post);  // (3)
        member.setMemberId(1L);     // (4)

        // (5)
        given(memberService.createMember(Mockito.any(Member.class)))
                .willReturn(member);

        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 객체를 생성한 후 필드에 주입(DI)
  2. @Autowired
    : MemberMapper를 DI 받는 이유는 MockMemberService의 createMember()에서 리턴하는 Member 객체 생성하기 위해
  3. MemberMapper를 이용해 post 변수를 Member 객체로 변환
    (사용하지 않고 new Member()와 같이 Member 객체 생성 가능함)
  4. createMember()의 리턴값(Member 객체)에는 memberId가 포함이 되는데 이 memberId는 response의 LocationHeader에 포함이 되어야 하므로 MockMemberService의 createMember()에서도 memberId를 리턴해 줄 수 있도록 memberId 추가
  5. Mockito에서 지원하는 Stubbing 메서드
    :  given()은 Mock 객체가 특정 값을 리턴하는 동작을 지정하는 데 사용, Mockito에서 지원하는 when()과 동일한 기능
    : Mock 객체인 memberService 객체로 createMember() 메서드를 호출하도록 정의함
    : Mockito.any(Member.class)는 Mockito에서 지원하는 변수 타입 중 하나 
      → 실제 MemberService 클래스에서 createMember()의 파라미터 타입이 Member 타입이기 때문에 Member.class 타입 지정
    : .willreturn(member)는 MockMemberService의 createMember() 메서드가 리턴할 Stub 데이터를 리턴
Stubbing?
: 테스트를 위해서  Mock 객체가 항상 일정한 동작을 하도록 지정하는 것 

BELATED ARTICLES

more