예를들어 다음과 같은 데이터 구성이 있다.
유저정보 내 연결된 SNS 계정을 등록해야 한다.
그런데 SNS계정은 1개 이상 필수이며, SNS 유형과 ID가 필수여야한다.
클래스로 표현하면 다음과 같다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class RequestUser {
@NotNull(message = "유저이름은 필수입니다")
private String userName;
@NotNull(message = "SNS ID는 1개 이상 등록되어야 합니다(1)")
@Size(min = 1, message = "SNS ID는 1개 이상 등록되어야 합니다(2)")
private List<SnsAccount> snsAccounts;
}
@Getter
@NoArgsConstructor
@AllArgsConstructor
class SnsAccount {
@NotNull(message = "SNS 유형은 필수입니다")
private String snsType;
@NotNull(message = "SNS id는 필수입니다")
private String snsId;
}
SnsAccount를 @RequestBody로 받아오려 하는데, 해당 클래스의 null, 크기, 그리고 그 안의 객체의 각 값들이 제대로 들어있는지를 점검하는 것이다.
위 상태에서 valid를 실행하면 테스트가 모두 통과된다. 즉 SnsAccount 내 값이 null이라 하더라도 넘어간다는 뜻이다.
우선 점검하고 싶은것 위주로 하나씩 테스트 작성해보자.
우선은 null을 체크하는 것부터 만들었다.
import org.hibernate.validator.HibernateValidator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import javax.validation.ConstraintViolation;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
class SnsAccountTest {
private LocalValidatorFactoryBean validator;
@BeforeEach
void init() {
validator = new LocalValidatorFactoryBean();
validator.setProviderClass(HibernateValidator.class);
validator.afterPropertiesSet();
}
@Test
@DisplayName("notNull 체크")
void checkNotNullTest() {
// given
RequestUser request = new RequestUser("아이유", null);
// when
Set<ConstraintViolation<RequestUser>> validate = validator.validate(request);
Iterator<ConstraintViolation<RequestUser>> iterator = validate.iterator();
assertThat(true).isEqualTo(iterator.hasNext());
// then
while (iterator.hasNext()) {
ConstraintViolation<RequestUser> next = iterator.next();
String message = next.getMessage();
System.out.println("message = " + message);
assertThat("SNS ID는 1개 이상 등록되어야 합니다(1)").isEqualTo(message);
}
}
}
SnsAccouts 에 값이 null 이므로 관련 체크가 되었고, 메세지를 리턴했다.(테스트 정상)
그럼 이번에는 size가 0 이상인 것을 체크해보도록 하자
...
@Test
@DisplayName("list 에서 1개이상 등록")
void checkListMore1Test() {
// given
List<SnsAccount> snsAccounts = new ArrayList<>();
SnsAccount snsAccount1 = new SnsAccount();
snsAccounts.add(snsAccount1);
RequestUser request = new RequestUser("아이유", snsAccounts);
// when
Set<ConstraintViolation<RequestUser>> validate = validator.validate(request);
Iterator<ConstraintViolation<RequestUser>> iterator = validate.iterator();
// then
assertThat(false).isEqualTo(iterator.hasNext());
}
...
마찬가지로 성공했다.
사실 이 테스트는 실패했어야 한다. 왜냐하면 SnsAccount 내에 @NotNull을 설정해두었기 때문이다. 코드를 보면 snsAccount1을 생성할때 값이 아무것도 없는 기본생성자로 생성했기에 안내문구가 나와야 하는데 그러지 않았다.
List에 포함되는 클래스도 Valid 체크를 하려면 List 위에 @Valid 어노테이션을 추가해야한다. 다음과 같다.
...
@Valid
@NotNull(message = "SNS ID는 1개 이상 등록되어야 합니다(1)")
@Size(min = 1, message = "SNS ID는 1개 이상 등록되어야 합니다(2)")
private List<SnsAccount> snsAccounts;
...
@Getter
@NoArgsConstructor
@AllArgsConstructor
class SnsAccount {
@NotNull(message = "SNS 유형은 필수입니다")
private String snsType;
@NotNull(message = "SNS id는 필수입니다")
private String snsId;
}
똑같은 테스트를 다시 실행해보면 이번엔 실패한다.
에러가 발생했기 때문에 iterator.hasNext() 가 true인 것이다.
테스트코드를 조금 수정해서 메세지를 살펴보자.
...
@Test
@DisplayName("list 에서 1개이상 등록")
void checkListMore1Test() {
// given
List<SnsAccount> snsAccounts = new ArrayList<>();
SnsAccount snsAccount1 = new SnsAccount();
snsAccounts.add(snsAccount1);
RequestUser request = new RequestUser("아이유", snsAccounts);
// when
Set<ConstraintViolation<RequestUser>> validate = validator.validate(request);
Iterator<ConstraintViolation<RequestUser>> iterator = validate.iterator();
assertThat(true).isEqualTo(iterator.hasNext());
// then
while (iterator.hasNext()) {
ConstraintViolation<RequestUser> next = iterator.next();
String message = next.getMessage();
System.out.println("message = " + message);
}
}
...
이제 null에 대한 메세지처리가 제대로 나온다.
그럼 이제 통과할 테스트를 작성해보자.
...
@Test
@DisplayName("sns not null 체크")
void checkListNotNullTest() {
// given
List<SnsAccount> snsAccounts = new ArrayList<>();
SnsAccount snsAccount1 = new SnsAccount("KAKAO", null);
snsAccounts.add(snsAccount1);
RequestUser request = new RequestUser("아이유", snsAccounts);
// when
Set<ConstraintViolation<RequestUser>> validate = validator.validate(request);
Iterator<ConstraintViolation<RequestUser>> iterator = validate.iterator();
assertThat(true).isEqualTo(iterator.hasNext());
// then
while (iterator.hasNext()) {
ConstraintViolation<RequestUser> next = iterator.next();
String message = next.getMessage();
System.out.println("message = " + message);
assertThat("SNS id는 필수입니다").isEqualTo(message);
}
}
...
SNS ID는 일부로 Null을 넣어 비교했고 테스트 성공이 되었다.
결론
서브클래스에 유효성을 체크하고 싶다면 해당 클래스를 변수에 담는 곳에 @Valid를 추가한다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class RequestUser {
@NotNull(message = "유저이름은 필수입니다")
private String userName;
@Valid // <<<<<<<<<< 이부분
@NotNull(message = "SNS ID는 1개 이상 등록되어야 합니다(1)")
@Size(min = 1, message = "SNS ID는 1개 이상 등록되어야 합니다(2)")
private List<SnsAccount> snsAccounts;
}
끝.
'공부 > 프로그래밍' 카테고리의 다른 글
[aws] lambda@edge 설정 중 파라미터(query string)이 넘어오지 않는 경우(이미지 리사이징) (0) | 2021.02.08 |
---|---|
[springboot] swagger 설정 & 사용법 (1) | 2021.02.04 |
[java] lambda 를 이용한 GroupBy mulitiple field 사용하기 (1) | 2021.01.20 |
[retrofit, gson] Expected BEGIN_OBJECT but was STRING 에러 해결(String -> LocalDate) (1) | 2021.01.18 |
[jpa] 쿼리 로그 설정 (0) | 2021.01.15 |
댓글