Skip to content

[미니세미나] MockMvc, Mockito

Toa edited this page Feb 21, 2023 · 3 revisions

MockMvc

MockMvc는 Spring MVC 어플리케이션을 테스트하는 프레임워크입니다. MockMvc를 통해 HTTP 요청과 응답을 시뮬레이션해보며 컨트롤러와 View에 대한 테스트를 실행할 수 있습니다.

주요 기능

  • HTTP 요청과 응답을 시뮬레이션을 해볼 수 있습니다.
  • 컨트롤러 메서드와 매핑을 테스트 해볼 수 있습니다.
  • HTTP 응답 내용이 의도한 바와 같은지 확인할 수 있습니다.
  • View의 랜더링과 내용에 대해 테스트할 수 있습니다.

예시

컨트롤러 코드

@RestController
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/api/user/signup")
    public ResponseEntity<?> postSignUp(@RequestBody PostSignUpReq postSignUpReq) {
        if (postSignUpReq.hasNull())
            return new CustomException(ExceptionType.POST_ACCOUNT_FORM_INVALID).getResponseEntity();
        PostSignUpRes postSignUpRes = userService.join(postSignUpReq);
        return new ResponseEntity<>(postSignUpRes, HttpStatus.CREATED);
    }
}

MockMvc 요청 설정 메서드

  • param/params : 요청 쿼리 스트링 설정
  • cookie : 요청 쿠키 설정
  • header/headers : 요청 헤더 설정
  • content : 요청 본문 설정
  • contentType : 요청 본문 타입 설정

테스트 코드

@WebMvcTest(UserController.class)
class UserControllerTest {
    @MockBean
    UserService userService;
    @Autowired
    private MockMvc mockMvc;

    @Test
    @DisplayName("회원가입 테스트")
    void signupTest() throws Exception {
        //given
        given(userService.join(any(PostSignUpReq.class))).willReturn(
                new PostSignUpRes(1000L)
        );

        //when
        mockMvc.perform(
                        post("/api/user/signup")
                                .contentType(MediaType.APPLICATION_JSON)
                                .content("{\"email\":\"[email protected]\"," +
                                        "\"password\":\"1234\"," +
                                        "\"name\":\"signupTest\"," +
                                        "\"phone\":\"01042427272\"}")
                )
                .andExpect(status().isCreated())
                .andExpect(jsonPath("success").exists())
                .andExpect(jsonPath("userId").exists())
                .andDo(print());

        // verify : 해당 객체의 메소드가 실행 여부를 체크
        verify(userService).join(any(PostSignUpReq.class));
    }
}

Mockbean

MockBean 어노테이션은 Spring Framework에 의해 제공되는 것으로 이 어노테이션이 붙은 빈에 대한 mock 객체를 제공합니다. Mock 객체는 테스트 동안 실제 빈을 대체하여 사용되고 given 메서드를 통해 mock 객체의 특정 메서드가 실행될 때 정해진 리턴을 하도록 설정할 수 있습니다.

Mockbean을 사용하는 이유

위의 예시에서 UserController는 UserService에 의존하고 있습니다. 만약 UserService를 Mockbean으로 대체하지 않고 테스트를 진행한다면 테스트가 실패해도 컨트롤러의 문제인지, 서비스의 문제인지, DB의 문제인지 알기 어려워집니다. 따라서 의존 관계를 분리하고 테스트를 진행하기 위해 Mockbean을 사용하여 테스트를 진행합니다.

Mockito

Mockito는 테스트를 위해 Mock 객체들을 생성하고 실제 객체의 행위을 simulate하도록 설정할 수 있는 자바 라이브러리 입니다.

주요 기능들

  • 인터페이스와 클래스들의 Mock 객체들을 생성할 수 있습니다.
  • 메서드 stub을 이용하여 Mock 객체의 행위를 지정할 수 있습니다.
  • 예상한 대로 mock 객체가 사용되었는지 verify 메서드를 이용해 검증할 수 있습니다.

사용하는 이유

Mockbean과 동일하게 의존 관계의 복잡도를 낮추고 단위 테스트를 진행하기 위해 사용합니다.

예시

유저 서비스 코드

@Service
public class UserService {
    public PostSignUpRes join(PostSignUpReq req) {
        validateSignUp(req);
        Account student = userRepo.createAccountInfo(req.getName(), req.getPhone(), "Student");
        String hashPassword = BCrypt.hashpw(req.getPassword(), BCrypt.gensalt());
        userRepo.createLoginInfo(req.getEmail(), hashPassword, student.getId());
        return new PostSignUpRes(student.getId());
    }
}

서비스 테스트 코드

@SpringBootTest(classes = {UserService.class})
class UserServiceTest {
    @Test
    @DisplayName("회원 가입 서비스 메서드 테스트")
    void join() {
        //given
        PostSignUpReq postSignUpReq = new PostSignUpReq(email, name, phone, password);

        //when
        Mockito.when(userRepo.findByPhone(phone)).thenReturn(Optional.empty());
        Mockito.when(userRepo.findLoginInfoByEmail(email)).thenReturn(Optional.empty());
        Mockito.when(userRepo.createAccountInfo(name, phone, type))
                .thenReturn(account);
        Mockito.when(userRepo.createLoginInfo(email, password, accountId))
                .thenReturn(loginInfo);
        PostSignUpRes joinResDto = userService.join(postSignUpReq);

        //then
        assertThat(joinResDto.getUserId()).isEqualTo(accountId);
    }
}