스프링 공부/게시판 프로젝트 만들기

[스프링] 37. MemberController 조회, 삭제 기능 만들기

장아장 2023. 2. 20. 20:49
http.exceptionHandling()
        .authenticationEntryPoint(jwtAuthenticationEntryPoint)
        .accessDeniedHandler(jwtAccessDenialHandler)
        .and()
        .authorizeRequests()
        .antMatchers("/api/auth/sign_in", "/api/auth/join").permitAll()
        .antMatchers("/api/auth/reissue").access("hasAuthority('USER') or hasAuthority('MANAGER') or hasAuthority('ADMIN')")
        .antMatchers("/api/members/**").access("hasAuthority('USER') or hasAuthority('MANAGER') or hasAuthority('ADMIN')")
        .and()
        .apply(new JwtSecurityConfig(tokenProvider));
return http.build();

일단 SecurityConfig에 member에 대해서 다음과 같이 설정해주었다. 

 

이후, 기존 MemberService의 search테스트를 그대로 가져와, 테스트메서드 구조만 조금 바꾸어주었다. 

@Test
@DisplayName("토큰이 없으면, 401에러를 반환한다.")
public void searchNoToken_FAIL() throws Exception{
    //given
    SearchMemberDto searchMemberDto = SearchMemberDto.builder()
            .username(null)
            .email(null)
            .nickname(null)
            .build();
    //expected
    mvc.perform(MockMvcRequestBuilders.get("/api/members/search")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(makeJson(searchMemberDto)))
            .andExpect(MockMvcResultMatchers.status().isUnauthorized())
            .andDo(MockMvcResultHandlers.print());
}

@Test
@DisplayName("검색 파라미터가 전부 null이면 400에러와, 검색조건이 없음을 반환한다.")
public void searchAllNull_FAIL() throws Exception{
    //given
    TokenResponseDto tokenResponseDto = authService.signIn(SignInRequestDto.builder()
            .username("test1")
            .password("test1").build());
    SearchMemberDto searchMemberDto = SearchMemberDto.builder()
            .username(null)
            .email(null)
            .nickname(null)
            .build();
    //expected
    mvc.perform(MockMvcRequestBuilders.get("/api/members/search")
            .header("Authorization", "Bearer ".concat(tokenResponseDto.getAccessToken()))
            .header("RefreshToken", "Bearer ".concat(tokenResponseDto.getRefreshToken()))
            .contentType(MediaType.APPLICATION_JSON)
            .content(makeJson(searchMemberDto)))
            .andExpect(MockMvcResultMatchers.status().isBadRequest())
            .andDo(MockMvcResultHandlers.print());
}

@Test
@DisplayName("test라는 아이디를 기준으로 1페이지를 검색하면 test1~test10이 출력된다.")
public void searchAll_Success() throws Exception{
    //given
    TokenResponseDto tokenResponseDto = authService.signIn(SignInRequestDto.builder()
            .username("test1")
            .password("test1").build());
    SearchMemberDto searchMemberDto = SearchMemberDto.builder()
            .username("test")
            .email(null)
            .nickname(null)
            .build();
    //expected
    mvc.perform(MockMvcRequestBuilders.get("/api/members/search?page={}", 1)
                    .header("Authorization", "Bearer ".concat(tokenResponseDto.getAccessToken()))
                    .header("RefreshToken", "Bearer ".concat(tokenResponseDto.getRefreshToken()))
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(makeJson(searchMemberDto)))
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andExpect(MockMvcResultMatchers.jsonPath("$.success").value(true))
            .andExpect(MockMvcResultMatchers.jsonPath("$.code").value(200))
            .andExpect(MockMvcResultMatchers.jsonPath("$.result.data.content.length()").value(10))
            .andExpect(MockMvcResultMatchers.jsonPath("$.result.data.content.[0].username").value("test1"))
            .andDo(MockMvcResultHandlers.print());
}

이런식으로 만들어주었다(사실 코드 자체를 그대로 가져오는 것은, 컨트롤러 테스트방식과 서비스 테스트방식의 차이말고는 똑같기에 의미가 없다고 판단했다. 모든 테스트에 서비스 + 토큰의 경우 정도만 생각하면 된다. )

 

@Test
@DisplayName("회원 삭제를 성공하면 성공문구와 200코드를 반환한다.")
public void delete_Success() throws Exception{
    //given
    authService.registerNewMember(RegisterRequestDto.builder()
            .username("test")
            .nickname("test")
            .email("test@test.com")
            .password("test")
            .passwordCheck("test").build());
    TokenResponseDto tokenResponseDto = authService.signIn(SignInRequestDto.builder()
            .username("test")
            .password("test").build());
    //expected
    mvc.perform(MockMvcRequestBuilders.delete("/api/members/delete")
                    .header("Authorization", "Bearer ".concat(tokenResponseDto.getAccessToken()))
                    .header("RefreshToken", "Bearer ".concat(tokenResponseDto.getRefreshToken())))
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andExpect(MockMvcResultMatchers.jsonPath("$.success").value(true))
            .andExpect(MockMvcResultMatchers.jsonPath("$.code").value(200))
            .andExpect(MockMvcResultMatchers.jsonPath("$.result.data").value("회원이 삭제되었습니다. 그동한 감사합니다."));
}

삭제에 대한 테스트도 만들었다. 

회원 탈퇴가 필요할 수 있다고 판단했기 때문이다. 

@Transactional
public String deleteMember(Member member){
    memberRepository.findByUsername(member.getUsername()).orElseThrow(MemberNotFoundException::new);
    memberRepository.delete(member);
    return "회원이 삭제되었습니다. 그동한 감사합니다.";
}

삭제에 대한 서비스 로직도 간단하게 만들어주었다. 

 

Member에 대해서도 마무리가 되었다. 

물론, 나중에 다시 돌아올 수 있다. 

왜냐하면, 게시판에서 마이페이지를 가면, 내가 쓴 게시물들이 나와야 한다. 

나중에 Post에 대한 기능들을 만들면서, 이에 대해서도 Member로 돌아와 구현해야겠다.