[1년 후 마실가실] Custom Exception
1년 전 진행했던 마실가실 프로젝트를 🛠️리팩토링하며 정리한 내용입니다.
회원 가입을 진행할 때, Email 중복 검사하는 로직을 추가했습니다.
처음에는 Email로 조회해서 리스트의 갯수가 0일 경우 통과하는 로직으로 작성했습니다.
그 다음으로는 JPA 강의를 들으면서 정리한 코드를 살펴보았는데,
Exceopion이 왜 거기서 나와...?
public void validateDuplicateMember(Member member) {
List<Member> findMembers = memberRepository.findByName(member.getName());
if(!findMembers.isEmpty()){
throw new IllegalStateException("이미 존재하는 회원입니다.");
}
}
그대로 코드를 사용할 수는 있지만, IllegalStateException 대신 CustomException을 사용해보고 싶었습니다.
왜냐면 HttpStatus도 함께 사용하는 멋진 코드를 발견했기 때문이죠.
그렇기에 이 글을
- Error Code를 Enum 형태로 만들고
- CustomException을 만들어
- Test Code를 작성해 본다
를 정리한 글입니다.
1. Error code Enum 생성
package com.msgs.msgs.error;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
public enum ErrorCode {
// 회원
CHECK_LOGIN_ID_OR_PASSWORD(HttpStatus.NOT_FOUND, "아이디 또는 비밀번호를 확인해주세요."),
DUPLICATED_EMAIL(HttpStatus.BAD_REQUEST, "이미 존재하는 이메일 입니다.");
private final HttpStatus httpStatus;
private final String message;
ErrorCode(HttpStatus httpStatus, String message) {
this.httpStatus = httpStatus;
this.message = message;
}
}
제가 알던 Enum과는 모양이 달라서 많이 놀랐습니다.
Enum은 아래와 같이 간단한 열거형만 써봤기 때문이죠.
public enum ErrorCode {
CHECK_LOGIN_ID_OR_PASSWORD,
DUPLICATED_EMAIL,
}
Enum 요소에 특정 값을 연결하려면 필드값을 추가해주면 됩니다.
Enum과 필드값을 매핑해주면, if문의 사용을 줄여 가독성을 높일 수 있습니다.
이 때, 유의해야 할 점은 반드시 Enum 값 선언 이후에 이후에 필드/생성자가 위치해야 한다는 것입니다.
그리고 Enum class에서 자체적으로 name()를 제공하기 때문에, 필드값을 name을 사용하지 않는 것이 좋습니다.
+ Enum은 Enum 값으로 데이터를 찾을 수 있지만 필드의 경우에는 따로 메서드를 만들어 줘야 합니다.
// HttpStatus -> ErrorCode 조회
private static final Map<HttpStatus, ErrorCode> BY_HTTPSTATUS =
Stream.of(values()).collect(Collectors.toMap(ErrorCode::getHttpStatus, e -> e));
public static Optional<ErrorCode> valueOfHttpStatus(HttpStatus httpStatus){
return Optional.ofNullable(BY_HTTPSTATUS.get(httpStatus));
}
// Message -> ErrorCode 조회
private static final Map<String, ErrorCode> BY_MESSAGE =
Stream.of(values()).collect(Collectors.toMap(ErrorCode::getMessage, e -> e));
public static Optional<ErrorCode> valueOfMessage(String message){
return Optional.ofNullable(BY_MESSAGE.get(message));
}
2. CustomException 생성
ErrorCode를 받아주는 CustomException을 만들어줍니다.
@Getter
public class BusinessException extends RuntimeException{
private ErrorCode errorCode;
public BusinessException(ErrorCode errorCode) {
this.errorCode = errorCode;
}
}
RuntimeException도 상속을 받습니다.
3. Test Code 작성
1 기능, 1 테스트 코스..
특히 테스트 코드는 익숙하지 않기 때문에 기능에 맞춰 계속 추가해 볼 예정입니다.
@SpringBootTest
@Transactional
public class UserServiceTest {
// ...
@Test
@DisplayName("이메일이 동일한 회원이 존재할 경우, 예외가 발생한다.")
public void emailDuplicateCheck() throws Exception {
// given
User userA = new User();
userA.setStatus("M");
userA.setEmail("test@email.com");
userA.setPhone("01023456789");
userService.create(userA);
String existingEmail = "test@email.com";
// when
// then
BusinessException exception = assertThrows(BusinessException.class,
() -> userService.emailDuplicateCheck(existingEmail));
assertEquals(DUPLICATED_EMAIL, exception.getErrorCode());
}
}
🙋♀️
본 포스트는 공부 목적으로 작성하였습니다.
보시는 도중 잘못된 부분이나 개선할 부분이 있다면 댓글로 알려주시면 수정하도록 하겠습니다.
📑
참고 자료