지난 포스트에서 @Valid
를 사용하여 유효성 검사를 진행했는데 값이 빈 값인지 체크하는 것 이외에도 다른 유효성 검사를 추가로 해야해서 유효성 검사를 추가하려고 한다.
@Transactional
@Override
public MemberVo join(MemberDto md){
//join에 대한 유효성 검사 method
joinValidation(md);
String id = md.getId();
String pw = md.getPw();
String email = md.getEmail();
Set<String> roles = new HashSet<>();
roles.add(MemberRoles.MEMBER.getRole());
MemberEntity me = MemberEntity.builder()
.id(id)
.pw(passwordEncoder.encode(pw)) //비밀번호 암호화
.email(email)
.auth(roles)
.build();
MemberEntity save = loginRepository.save(me);
return MemberVo.builder().id(save.getId()).build();
}
//그 외 유효성 검사
private void joinValidation(MemberDto md){
//pw와 rePw이 같은 값인지 체크
if(!md.getPw().equals(md.getRePw())) throw new JoinValidException(JoinValidExceptionMsg.RE_PW_FAIL.getMsg(), HttpStatus.BAD_REQUEST);
//email 형식 체크
if(!md.getEmail().contains("@")) throw new JoinValidException(JoinValidExceptionMsg.EMAIL_FAIL.getMsg(), HttpStatus.BAD_REQUEST);
}
그 후에 joinValidation()
메서드를 추가로 작성하여 내가 하려는 유효성 검사를 진행했다.
@AllArgsConstructor
@Getter
public enum JoinValidExceptionMsg {
RE_PW_FAIL("두 비밀번호가 일치하지 않습니다."),
EMAIL_FAIL("이메일 형식을 확인해주세요.")
;
private String msg;
}
테스트 코드를 작성하기 전 유효성 검사 에러 메세지와 테스트 코드 기대 에러 메세지의 내용을 좀 더 코드로 보여주기 쉽게 만들기 위해 enum 클래스를 작성했다.
유효성 검사의 Exception을 진행하기 위해 Exception의 생성자와 advice의 코드를 수정했다.
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class JoinValidException extends RuntimeException {
private String msg;
private HttpStatus status;
private List<ObjectError> allErrors = new LinkedList<>();
public JoinValidException(String msg, HttpStatus status) {
this.msg = msg;
this.status = status;
}
}
오류 list가 없을 경우를 위해 컬렉션 객체를 받지 않는 생성자를 추가로 만들었다.
@ExceptionHandler(JoinValidException.class)
public ResponseEntity joinValidException(JoinValidException jve){
List<ObjectError> allErrors = jve.getAllErrors();
List<CommonError> errorList = new ArrayList<>();
if(allErrors.isEmpty()){
CommonError commonError = new CommonError(jve.getMsg());
errorList.add(commonError);
}else{
for(ObjectError oe : allErrors){
String detail = ((FieldError)oe).getField() + " " + oe.getDefaultMessage();
CommonError commonError = new CommonError(jve.getMsg(), detail);
errorList.add(commonError);
}
}
CommonErrorV1<List<CommonError>> result = new CommonErrorV1<>(errorList);
return new ResponseEntity<CommonErrorV1>(result, jve.getStatus());
}
advice 또한 컬렉션 객체가 들어왔을 때와 들어오지 않았을 때를 분기처리하여 작성하였다.
@SpringBootTest
@Transactional(readOnly = true)
class LoginServiceImplTest {
@Autowired
LoginService loginService;
@Test
@DisplayName("rePw 불일치")
void joinRePwFail(){
//given
MemberDto md = new MemberDto();
md.setId("testId");
md.setPw("password1");
md.setRePw("password2"); //불일치
md.setEmail("mail@mail.com");
//when
JoinValidException joinValidException = assertThrows(JoinValidException.class, () -> loginService.join(md));
//then
assertEquals(JoinValidExceptionMsg.RE_PW_FAIL.getMsg(),joinValidException.getMsg());
}
@Test
@DisplayName("잘못된 email 형식")
void joinEmailFail(){
//given
MemberDto md = new MemberDto();
md.setId("testId");
md.setPw("password1");
md.setRePw("password1");
md.setEmail("mail.com"); //형식 오류
//when
JoinValidException joinValidException = assertThrows(JoinValidException.class, () -> loginService.join(md));
//then
assertEquals(JoinValidExceptionMsg.EMAIL_FAIL.getMsg(),joinValidException.getMsg());
}
}
지난 포스트에서는 통합 테스트를 진행했다면 이번 포스트에서는 단위 테스트
를 진행한다. 통합 테스트도 중요하지만 단위 테스트는 class나 method 단위로 테스트를 진행하기 때문에 매우 중요하다.