이번에는 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));
}
}
궁금한신점이나 잘못된 부분이 있으면 자유롭게 댓글 달아주세요.
'spring > 게시판 api' 카테고리의 다른 글
Spring boot 게시판 API 서버 제작 (10) - 로그인 - 인증 로직 테스트 (0) | 2023.02.21 |
---|---|
Spring boot 게시판 API 서버 제작 (9) - 로그인 - 인증 로직 (0) | 2023.02.20 |
Spring boot 게시판 API 서버 제작 (7) - 로그인 - Exception 처리 (0) | 2023.02.19 |
Spring boot 게시판 API 서버 제작 (6) - 로그인 - 웹 계층 구현 (0) | 2023.02.19 |
Spring boot 게시판 API 서버 제작 (5) - 로그인 - 서비스 로직 구현 (0) | 2023.02.18 |