728x90

이전글

 

[03] 게시된 포스트 삭제

이전글 [03] 게시된 포스트 수정 이전글 [03] 게시된 모든 포스트 목록 보기 이전글 [03] 포스트 등록 만들기 체크 사항 로그인이 되어있어야 하며, 토큰으로 인증을 통과해야 한다. 회원만이 글 작

chordplaylist.tistory.com

목표

  • 1. controller / 2. service로 나눠서 테스트를 진행해야 함.
  • 1. 성공, 2. 실패 테스트 케이스를 모두 통과하는 실제 코드 작성.
  • Exception 처리는 enum Error코드에 작성 후 호출 해서 사용
    • 실패의 경우 enum값의 errorCode로 처리하기
  • when(어떤 상황일 때)를 각각 설계해 보고, Test case에 따라 예상되는 결괏값을 작성해 주기
  • Controller, Service 두 클래스의 테스트 코드 작성하기

체크사항

회원가입

controller

  • 회원가입 성공
  • 회원가입 실패 - userName 중복(이미 가입된 회원이 있는 경우)

로그인

controller

  • 로그인 성공
  • 로그인 실패 - userName 없음(가입이 되어있지 않은 경우)
  • 로그인 실패 - password 오류.

User Controller Test

basic

@WebMvcTest(UserController.class)
@WithMockUser
class UserControllerTest {
    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    @MockBean
    UserService userService;

    private String token;

    @Value("${jwt.secret}")
    private String secretKey;

    @BeforeEach()
    public void getToken() {
        long expireTimeMs = 1000 * 60 * 60;
        token = JwtUtil.createJwt("chordpli", secretKey, System.currentTimeMillis() + expireTimeMs);
    }
}
  1. @SpringBootTest가 아닌, @WebMvcTest를 사용하였습니다.
    • @SpringBootTest를 사용하면 스프링이 구동되면서 모든 빈을 로드하기 때문에 시간이 오래 걸리고, 단위가 커져서 세부적인 테스트를 하기 어려워지기 때문입니다.
  2. @WithMockUser 어노테이션을 사용해서 Spring Security 인증을 받아옵니다.
  3. @Autowired를 사용해서 의존성을 주입합니다.
    • MockMvc, ObjectMapper의 의존성을 주입합니다.
  4. @MockBean을 사용해서 UserService를 선언합니다.
  5. token을 발급하는 상황을 가정하기 위해 secretKey, token, getToken()을 만들고 선언하였습니다.

회원가입 Test

회원가입 성공

...
class UserControllerTest {
    ...

    /* 회원가입 */
    @Test
    @DisplayName("회원가입 성공")
    void join_success() throws Exception {
        UserDto userDto = UserDto.builder()
                .id(1)
                .userName("jun")
                .password("abcd")
                .userRole(UserRole.USER)
                .build();

        UserJoinRequest request = new UserJoinRequest("jun", "abcd");

        given(userService.join(any()))
                .willReturn(userDto);

        String url = "/api/v1/users/join";
        mockMvc.perform(post(url).with(csrf())
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsBytes(request)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.resultCode").exists())
                .andExpect(jsonPath("$.resultCode").value("SUCCESS"))
                .andExpect(jsonPath("$.result.userId").exists())
                .andExpect(jsonPath("$.result.userId").value(1))
                .andExpect(jsonPath("$.result.userName").exists())
                .andExpect(jsonPath("$.result.userName").value("jun"))
                .andDo(print());

        verify(userService, times(1)).join(any());
    }
}
  1. 회원가입 후 생성되는 UserDto를 생성합니다.
  2. 회원가입할 때 필요한 정보를 받을 UserJoinRequest를 생성합니다.
  3. userService.join을 했을 때, userDto를 반환받습니다.
  4. post형식으로 url에 요청을 보내고 그 요청에는 request가 담겨 있습니다.
  5. given 했을 때 우리는 userDto를 받기로 했기 때문에 userDto의 내용들이 잘 담겨있는지 andExpect를 사용해서 값들이 존재하는지, 값이 일치하는지 확인합니다.
  6. verify를 사용해서 userService의 join이 몇 번 사용됐는지 확인합니다.

회원가입 실패

...
class UserControllerTest {
    ...

    /* 회원가입 */
    @Test
    @DisplayName("회원가입 실패 - userName 중복")
    void join_fail() throws Exception {
        UserJoinRequest request = new UserJoinRequest("jun", "abcd");

        given(userService.join(any()))
                .willThrow(new SNSAppException(DUPLICATED_USER_NAME, DUPLICATED_USER_NAME.getMessage()));

        String url = "/api/v1/users/join";
        mockMvc.perform(post(url).with(csrf())
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsBytes(request)))
                .andExpect(status().isConflict())
                .andDo(print());
    }
}
  1. 회원가입할 때 필요한 정보를 받을 UserJoinRequest를 생성합니다.
  2. userService.join을 실행했을 때 DUPLICATED_USER_NAME예외를 던집니다.
  3. post형식으로 url에 요청을 보내고 그 요청에는 request가 담겨 있습니다.
  4. http status가 confilct가 맞는지 확인합니다.

로그인 테스트

로그인 성공

...
class UserControllerTest {
    ...
    /* 로그인 */
    @Test
    @DisplayName("로그인 성공")
    void login_success() throws Exception {
        UserDto userDto = UserDto.builder()
                .id(1)
                .userName("jun")
                .password("abcd")
                .userRole(UserRole.USER)
                .build();

        UserLoginRequest request = new UserLoginRequest(userDto.getUserName(), userDto.getPassword());
        UserLoginResponse response = new UserLoginResponse(token);
        given(userService.login(any())).willReturn(response);

        String url = "/api/v1/users/login";
        mockMvc.perform(post(url).with(csrf())
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsBytes(request)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.resultCode").exists())
                .andExpect(jsonPath("$.resultCode").value("SUCCESS"))
                .andExpect(jsonPath("$.result.jwt").exists())
                .andExpect(jsonPath("$.result.jwt").value(token))
                .andDo(print());
        verify(userService, times(1)).login(any());
    }
}
  1. UserDto를 만들고, Login 할 때 필요한 정보를 UserDto에서 가져옵니다.
  2. UserLoginResponse를 만들고 token 정보를 입력합니다.
  3. userService가 login을 사용할 때 token을 가지고 있는 UserLoginResponse가 반환되도록 합니다.
  4. post형식의 login url을 호출했을 때 request를 넘기고, 그에 따른 결과 값이 존재하는지, 원하는 값과 동일한지 확인합니다.

로그인 실패 - 사용자가 존재하지 않을 때

...
class UserControllerTest {
    ...

    /* 로그인 */
    ...
    @Test
    @DisplayName("로그인 실패_userName 없음")
    void login_fail_empty_user_name() throws Exception {
        UserDto userDto = UserDto.builder()
                .id(1)
                .userName("jun")
                .password("abcd")
                .userRole(UserRole.USER)
                .build();

        UserLoginRequest request = new UserLoginRequest("abc", "bbcd");

        given(userService.login(any()))
                .willThrow(new SNSAppException(USERNAME_NOT_FOUND, USERNAME_NOT_FOUND.getMessage()));

        String url = "/api/v1/users/login";
        mockMvc.perform(post(url).with(csrf())
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsBytes(request)))
                .andExpect(status().isNotFound())
                .andDo(print());
    }
}
  1. "abc"라는 userName을 가지고 있는 User가 없다고 가정합니다.
  2. userSerivce의 login을 사용했을 때, USERNAME_NOT_FOUND예외를 던져줍니다.
  3. post형식의 login url을 호출했을 때 request를 넘기고, 그에 따른 http status가 NotFound가 나왔는지 확인합니다.

로그인 실패 - password 불일치

...
class UserControllerTest {
    ...

    /* 로그인 */
    @Test
    @DisplayName("로그인 실패_password 오류")
    void login_fail_wrong_password() throws Exception {
        UserDto userDto = UserDto.builder()
                .id(1)
                .userName("jun")
                .password("abcd")
                .userRole(UserRole.USER)
                .build();

        UserLoginRequest dto = new UserLoginRequest(userDto.getUserName(), "bbcd");

        given(userService.login(any()))
                .willThrow(new SNSAppException(INVALID_PASSWORD, INVALID_PASSWORD.getMessage()));

        String url = "/api/v1/users/login";
        mockMvc.perform(post(url).with(csrf())
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsBytes(dto)))
                .andExpect(status().isUnauthorized())
                .andDo(print());
    }
}
  1. "jun"라는 userName을 가지고 있는 User의 비밀번호는 "abcd"입니다.
  2. 로그인하려는 dto의 비밀번호는 "bbcd"입니다.
  3. userSerivce의 login을 사용했을 때, INVALID_PASSWORD 예외를 던져줍니다.
  4. post형식의 login url을 호출했을 때 request를 넘기고, 그에 따른 http status가 isUnauthorized가 나왔는지 확인합니다.

다음글

 

[04] Post Test 코드 작성 - 1 (Controller Test)

이전글 [04] User Test 코드 작성 이전글 [03] 게시된 포스트 삭제 이전글 [03] 게시된 포스트 수정 이전글 [03] 게시된 모든 포스트 목록 보기 이전글 [03] 포스트 등록 만들기 체크 사항 로그인이 되어

chordplaylist.tistory.com

 

반응형
코드플리