spring/게시판 api

Spring boot 게시판 API 서버 제작 (8) - 로그인 - 조회, 삭제 로직

얼킴 2023. 2. 19. 22:20

이번에는 member를 조회하고 삭제하는 기능을 추가해 보겠습니다.

MemberDto 생성

먼저 Member 데이터 전송을 위한 MemberDto 객체를 생성합니다.

@Data //자동으로 필드에 대한 getter, setter, equals(), hashCode(), toString() 메서드 등을 생성
@AllArgsConstructor
@NoArgsConstructor
public class MemberDto {
    public Long id;
    private String email;
    private String username;
    private String nickname;

    public static MemberDto toDto(Member member){
        return new MemberDto(member.getId(), member.getEmail(), member.getUsername(), member.getNickname());
    }
}

기본 정보를 담고있는 필드와 Member 를 MemberDto로 변환해주는 static 함수를 추가해줍니다.

 

MemberService 생성

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {
    private final MemberRepository memberRepository;

    public MemberDto read(Long id){
        Member member = memberRepository.findById(id).orElseThrow(MemberNotFoundException::new); //회원 조회
        return MemberDto.toDto(member); // 회원 데이터 전송
    }

    @Transactional
    public void delete(Long id){
        if(notExistsMember(id)) throw new MemberNotFoundException(); //회원이 없으면 예외 발생
        memberRepository.deleteById(id); //회원 삭제
    }

    private boolean notExistsMember(Long id){ // id에 해당하는 회원 정보가 존재하지 않는지 확인
        return !memberRepository.existsById(id);
    }
}

MemberService에서는 회원을 조회하는 read함수와 회원을 삭제하는 delete함수가 있습니다.

 

MemberService 테스트

테스트는 이전 테스트들과 동일하게 진행 되므로 설명은 생략하겠습니다.

더보기
@ExtendWith(MockitoExtension.class)
class MemberServiceTest {
    @InjectMocks MemberService memberService;
    @Mock
    MemberRepository memberRepository;

    @Test
    public void readTest(){
        //given
        Member member = createMember();
        given(memberRepository.findById(anyLong())).willReturn(Optional.of(member));

        //when
        MemberDto result = memberService.read(1L);

        //then
        assertThat(result.getEmail()).isEqualTo(member.getEmail());
    }

    @Test
    void readExceptionByMemberNotFoundTest() {
        // given
        given(memberRepository.findById(any())).willReturn(Optional.ofNullable(null));

        // when, then
        assertThatThrownBy(() -> memberService.read(1L)).isInstanceOf(MemberNotFoundException.class);
    }

    @Test
    void deleteTest() {
        // given
        given(memberRepository.existsById(anyLong())).willReturn(true);

        // when
        memberService.delete(1L);

        // then
        verify(memberRepository).deleteById(anyLong());
    }

    @Test
    void deleteExceptionByMemberNotFoundTest() {
        // given
        given(memberRepository.existsById(anyLong())).willReturn(false);

        // when, then
        assertThatThrownBy(() -> memberService.delete(1L)).isInstanceOf(MemberNotFoundException.class);
    }


    private Member createMember() {
        return new Member("email@email.com", "123456a!", "username", "nickname", List.of());
    }

}

MemberController 생성

이번에는 API요청을 할 수 있도록 MemberController을 생성해보겠습니다.

@RestController
@RequiredArgsConstructor
@Slf4j
public class MemberController {
    private final MemberService memberService;

    @GetMapping("/api/members/{id}")
    @ResponseStatus(HttpStatus.OK)
    public Response read(@PathVariable Long id){
        return Response.success(memberService.read(id)); //회원 조회 후 테이터와 함께 성공 반환
    }

    @DeleteMapping("/api/members/{id}")
    @ResponseStatus(HttpStatus.OK)
    public Response delete(@PathVariable Long id) {
        memberService.delete(id); //회원 삭제
        return Response.success(); //성공 반환
    }
}

회원 조회의 경우 @GetMapping을 통해 HTTP GET 요청을 처리합니다. 그리고 @PathVariable 어노테이션을 붙여서 id값을 가져옵니다. 최종적으로 id를 통한 회원을 조회하고 성공 여부와 데이터를 같이 반환합니다.

회원 삭제의 경우에는 @DeleteMapping을 통해 HTTP DELETE 요청을 처리합니다. id를 통한 회원 삭제를 실행하고 성공 여부를 반환합니다.

 

MemberController 테스트

MemberController 테스트 역시 이전 테스트들과 동일하므로 설명 생략합니다.

더보기
@ExtendWith(MockitoExtension.class)
class MemberControllerTest {
    @InjectMocks
    MemberController memberController;
    @Mock
    MemberService memberService;
    MockMvc mockMvc;

    @BeforeEach
    void beforeEach() {
        mockMvc = MockMvcBuilders.standaloneSetup(memberController).build();
    }

    @Test
    void readTest() throws Exception {
        // given
        Long id = 1L;

        // when, then
        mockMvc.perform(
                        get("/api/members/{id}", id))
                .andExpect(status().isOk());
        verify(memberService).read(id);
    }

    @Test
    void deleteTest() throws Exception {
        // given
        Long id = 1L;

        // when, then
        mockMvc.perform(
                        delete("/api/members/{id}", id))
                .andExpect(status().isOk());
        verify(memberService).delete(id);
    }
}

MemberController Advice 테스트

추가로 MemberController를 생성하였으니 해당 클래스에 대해서 예외 테스트도 추가 하였습니다. 설명은 생략합니다.

더보기
@ExtendWith(MockitoExtension.class)
public class MemberControllerAdviceTest {
    @InjectMocks
    MemberController memberController;
    @Mock
    MemberService memberService;
    MockMvc mockMvc;

    @BeforeEach
    void beforeEach() {
        mockMvc = MockMvcBuilders.standaloneSetup(memberController).setControllerAdvice(new ExceptionAdvice()).build();
    }

    @Test
    void readMemberNotFoundExceptionTest() throws Exception {
        // given
        given(memberService.read(anyLong())).willThrow(MemberNotFoundException.class);

        // when, then
        mockMvc.perform(
                        get("/api/members/{id}", 1L))
                .andExpect(status().isNotFound())
                .andExpect(jsonPath("$.code").value(-1007));
    }

    @Test
    void deleteMemberNotFoundExceptionTest() throws Exception{
        // given
        doThrow(MemberNotFoundException.class).when(memberService).delete(anyLong());

        // when, then
        mockMvc.perform(
                        delete("/api/members/{id}", 1L))
                .andExpect(status().isNotFound())
                .andExpect(jsonPath("$.code").value(-1007));
    }

}

 


궁금한신점이나 잘못된 부분이 있으면 자유롭게 댓글 달아주세요.

github : https://github.com/jaeyeon423/spring_board_api