Spring Projcect/[팀플] In & Out 가계부

회원 정보 조회 및 수정 API

계란💕 2022. 10. 21. 00:26

 

  • UpdateMemberInput
<hide/>
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UpdateMemberInput {

    private String nickName;
    private String phone;
    private LocalDate birth;
    private String address;
    private String gender;
    private String memberPhotoUrl;

}

 

 

  • MemberDto
    • Member 엔티티를 직접 건드리지 않고 member 객체를 이용할 수 있다.
    • UpdateMemberInput과 거의 동일하다.
<hide/>
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MemberDto {

    private String nickName;
    private String phone;
    private LocalDate birth;
    private String address;
    private String gender;
    private String memberPhotoUrl;

    public static MemberDto toDto(Member member) {
        return MemberDto.builder()
            .address(member.getAddress())
            .birth(member.getBirth())
            .gender(member.getGender())
            .memberPhotoUrl(member.getMemberPhotoUrl())
            .nickName(member.getNickName())
            .phone(member.getPhone())
            .build();
    }

}

 

  • Service
<hide/>

@Override
public void updateInfo(String email, UpdateMemberInput input) {

    Member member = memberRepository.findByEmail(email).get();
    if (input.getNickName().contains(" ") ||
        input.getPhone().contains(" ") ||
        input.getAddress().contains(" ") ||
        input.getMemberPhotoUrl().contains(" ") ||
        input.getGender().contains(" ")) {
        throw new RuntimeException("회원 정보는 공백을 포함할 수 없습니다.");
    }

    String previousUsedPhone = member.getPhone();
    String previousUsedNickname = member.getNickName();

    if (previousUsedPhone.equals(input.getPhone())) {
        throw new RuntimeException("기존 연락처와 동일합니다.");
    }
    if (previousUsedNickname.equals(input.getNickName())) {
        throw new RuntimeException("기존 닉네임과 동일합니다.");
    }

    member.setNickName(input.getNickName());
    member.setPhone(input.getPhone());
    member.setBirth(input.getBirth());  // null()
    member.setAddress(input.getAddress());
    member.setGender(input.getGender());
    member.setMemberPhotoUrl(input.getMemberPhotoUrl());
    memberRepository.save(member);
}

 

  • Controller
<hide/>
@PutMapping("/member/info")
public ResponseEntity<?> updateInfo(/*Principal principal*/
    @RequestBody UpdateMemberInput input) {
//        String email = principal.getName();
    String email = "egg@naver.com";
    memberService.updateInfo(email, input);
    String message = "회원 정보를 변경했습니다.";
    return new ResponseEntity<>(message, HttpStatus.OK);
}

 

  • ImplTest
    • captor클래스: 어떤 순간의 값을 저장하는 클래스 , 어떤 형태의 값을 캡터할 것인지 클래스명을 쓴다.
    • 위처럼 설정하면 String 만 캡처 가능하다.
    • verify() 맨 뒤에서 캡터를 사용해야한다.
    • times(1): verify() 안에 있는 메서드를 한 번 실행한다.
    • getInfo()를 한 번 실행하는지 확인하겠다.
    • times()는 메서드가 실행 횟수를 체크한다.
    • any() : memberServiceIm 이 실행되는지만 확인하려면 getInfo() 안에 any()를 넣을 수도 있다.
    • given은 테스트메서드 내에서 반환형을 특별히 정해준다. 진짜 리포짓에서 찾아오는게 아니니까 리포짓에서 찾아온다 가정했을 때의 반환값인 member를 넣어준다.
    • 아래 테스트 메서드에서 findByEmail() 안에는 any() 또는 "egg@naver.com"둘 중 하나만 들어가야 통과되며 다른 값이 들어가면 테스트를 통과하지 못한다.
<hide/>
@Test
@DisplayName("회원 정보 수정 - 성공")
void updateInfo() {

    // given
    Member member = Member.builder()
        .email("egg@naver.com")
        .address("서울특별시")
        .phone("010-2222-0000")
        .birth(LocalDate.from(LocalDate.of(2000, 9, 30)))
        .gender("남")
        .nickName("강동원")
        .password("abc!@#12")
        .build();
    given(memberRepository.findByEmail(anyString())).willReturn(
        Optional.of(member)
    );

    // when
    UpdateMemberInput input = UpdateMemberInput.builder().address("강원도")
        .nickName("치킨")
        .phone("010-1111-2313")
        .birth(LocalDate.now())
        .memberPhotoUrl("c:")
        .gender("여")
        .address("강원도")
        .build();

    // then
    memberService.updateInfo("egg@naver.com", input);

}


@Test
@DisplayName("회원 정보 수정(공백 포함) - 실패 (1)")
void updateInfo_fail_blank() {

    // given
    Member member = Member.builder()
        .email("egg@naver.com")
        .address("서울특별시")
        .phone("010-2222-0000")
        .birth(LocalDate.from(LocalDate.of(2000, 9, 30)))
        .gender("남")
        .nickName("강동원")
        .password("abc!@#12")
        .build();
    given(memberRepository.findByEmail(anyString())).willReturn(
        Optional.of(member)
    );
    UpdateMemberInput input = UpdateMemberInput.builder().address("강원도")
        .nickName("치 킨")
        .phone("010-11 11-2313")
        .birth(LocalDate.now())
        .memberPhotoUrl("c :")
        .gender("여 ")
        .address("강 원도")
        .build();

    // when
    Exception exception = assertThrows(RuntimeException.class,
        () -> memberService.updateInfo(member.getEmail(), input));

    // then
    assertEquals(exception.getMessage(), "회원 정보에는 공백을 포함할 수 없습니다.");

}


@Test
@DisplayName("회원 정보 수정(이전의 닉네임과 동일) - 실패 (2)")
void updateInfo_fail_sameNickName() {

    // given
    Member member = Member.builder()
        .email("egg@naver.com")
        .address("서울특별시")
        .phone("010-2222-0000")
        .birth(LocalDate.from(LocalDate.of(2000, 9, 30)))
        .gender("남")
        .nickName("강동원")
        .password("abc!@#12")
        .build();
    given(memberRepository.findByEmail("egg@naver.com")).willReturn(
        Optional.of(member)
    );

    UpdateMemberInput input = UpdateMemberInput.builder().address("강원도")
        .nickName("강동원")
        .phone("010-1111-2313")
        .birth(LocalDate.now())
        .memberPhotoUrl("c:")
        .gender("여")
        .address("강원도")
        .build();

    // when
    Exception exception = assertThrows(RuntimeException.class,
        () -> memberService.updateInfo(member.getEmail(), input));

    // then
    assertEquals(exception.getMessage(), "기존 닉네임과 동일합니다.");

}


@Test
@DisplayName("회원 정보 수정(이전의 폰번호와 동일) - 실패(3)")
void updateInfo_fail_samePhoneNumber() {

    // given
    Member member = Member.builder()
        .email("egg@naver.com")
        .address("서울특별시")
        .phone("010-2222-0000")
        .birth(LocalDate.from(LocalDate.of(2000, 9, 30)))
        .gender("남")
        .nickName("강동원")
        .password("abc!@#12")
        .build();
    given(memberRepository.findByEmail(any())).willReturn(
        Optional.of(member)
    );
    // when
    UpdateMemberInput input = UpdateMemberInput.builder().address("강원도")
        .nickName("동원참치")
        .phone("010-2222-0000")
        .birth(LocalDate.now())
        .memberPhotoUrl("c:")
        .gender("여")
        .address("강원도")
        .build();

    RuntimeException exception = assertThrows(RuntimeException.class,
        () -> memberService.updateInfo(member.getEmail(), input));

    // then
    assertEquals(exception.getMessage(), "기존 연락처와 동일합니다.");

}

 

 

  • ctrl 테스트
    • 컨트롤러 테스트는 일단 성공 케이스만 작성한다.
<hide/>
@Test
@DisplayName("회원 정보 수정 - 성공")
void updateInfo() throws Exception {

    // given
    UpdateMemberInput input = UpdateMemberInput.builder().address("강원도")
        .nickName("치킨")
        .phone("010-1111-2313")
        .birth(LocalDate.now())
        .memberPhotoUrl("c:")
        .gender("여")
        .address("강원도")
        .build();
    String inputToJson = mapper.writeValueAsString(input);

    // when
    mockMvc.perform(
            put("/api/member/info")
                .contentType(MediaType.APPLICATION_JSON)


                .content(inputToJson))
        .andExpect(status().isOk())
        .andDo(print());
    ArgumentCaptor<UpdateMemberInput> captor = ArgumentCaptor.forClass(UpdateMemberInput.class);

    // then
    Mockito.verify(memberServiceImpl, times(1)).updateInfo(anyString(), captor.capture());
    assertEquals(captor.getValue().getPhone(), input.getPhone()); //
}

 

 

 

  • 오류: beanCreationException 빈 생성 오류
<hide/>
rg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.UncategorizedScriptException: Failed to execute database script from resource [URL [file:/C:/Users/Ran/Desktop/R/zerobase/team_project/rezero/server/build/resources/main/data.sql]]; nested exception is java.lang.IllegalArgumentException: 'script' must not be null or empty
  • 원인: data.sql 이라는 DB 관련 파일을 추가했는데 yml 파일이나 builde.gradle 파일에 관련추가하지 않았다.
  • 해결: data.sql 사용하고 있는 파일이 아니라서 삭제했다.