Controller 에서 Valid를 사용하고 있는데 잘 작동하는지 확인하고 싶은데 확인할 방법이 없었다.
그러다 방법을 찾게되서 정리.
테스트 방법은 두가지가 있다.
1) Validator 를 주입받아 체크하는 방법
2) WebMvcTest와 MockMvc 를 이용해 호출하여 체크하는 방법
각각의 방법에 차이점이 있는데, 2번의 경우 ControllerAdvice를 이용해 Exception을 핸들링하는 경우 전자방법보다 정해진 틀에 맞춰 테스트를 해야한다.
Valid에 맞지 않는 것을 배열에 담아 리턴하는데, 내 경우엔 화면에 보여질 걸 생각해서 ExceptionHandler에서 1개의 메세지만 추려 리턴한다. 때문에 Assertion를 할때 내가 예상하는 문구가 나오지 않을 수 있다. 혹은 에러케이스별로 다 만들던가. 그래서 여러개를 일부로 에러내서 한번에 점검하려는 것을 할 수 없다.
그럼 각각 알아보자
1) Validator 를 주입받아 체크하는 방법
컨트롤러 생성
@RestController
public class Test202008Controller {
@PostMapping("/202008/regist/member")
public void registMember(@RequestBody @Valid RequestRegistMember request) {
System.out.println("request.getName() = " + request.getName());
System.out.println("request.getAge() = " + request.getAge());
System.out.println("request.getAddress() = " + request.getAddress());
}
}
파라미터인 RequestRegistMember 클래스 생성
name, age, jobName 을 기본값으로 설정하고 address는 설정하지 않았다.
@Getter
@NoArgsConstructor
public class RequestRegistMember {
@NotBlank(message = "이름은 필수입니다")
private String name;
@Min(value = 20, message = "20살 이후부터 가입 가능합니다")
private int age;
@NotBlank(message = "직업은 필수입니다")
private String jobName;
private String address;
public RequestRegistMember(String name, int age, String jobName, String address) {
this.name = name;
this.age = age;
this.jobName = jobName;
this.address = address;
}
}
테스트 작성
age는 20세이상으로 했지만 9로 설정하고, jobName은 null로 넣는다.
age와 jobName 관련하여 메세지대로 리턴이 되는지 검토한다.
@WebMvcTest
class Test202008ControllerTest {
@Autowired
private Validator validatorInjected;
@Test
@DisplayName("validTest")
void validTest() {
// given
String name = "아이유";
int age = 9;
String jobName = null;
RequestRegistMember request = new RequestRegistMember(name, age, jobName, null);
// when
Set<ConstraintViolation<RequestRegistMember>> validate = validatorInjected.validate(request);
// then
Iterator<ConstraintViolation<RequestRegistMember>> iterator = validate.iterator();
List<String> messages = new ArrayList<>();
while (iterator.hasNext()) {
ConstraintViolation<RequestRegistMember> next = iterator.next();
messages.add(next.getMessage());
System.out.println("message = " + next.getMessage());
}
Assertions.assertThat(messages).contains("20살 이후부터 가입 가능합니다"
, "직업은 필수입니다");
}
}
결과
예상대로 직업은 필수값 입력을, 나이는 20살 이후부터 가능하다고 메세지를 받을 수 있다.
2) WebMvcTest와 MockMvc 를 이용해 호출하여 체크하는 방법
이번엔 MockMvc로 테스트를 진행한다
@WebMvcTest(Test202008Controller.class)
public class Test202008WebControllerTest {
@Autowired
MockMvc mvc;
@Test
@DisplayName("valid 테스트")
void validTest() throws Exception {
// given
MockHttpServletRequestBuilder builder = post("/202008/regist/member")
.content("{\"name\": \"아이유\", \"age\": 9}")
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mvc.perform(builder)
// .andExpect(status().isOk())
.andReturn();
String message = result.getResolvedException().getMessage();
System.out.println("message = " + message);
// 만약 ControllerAdvice를 이용하고 있다면 메세지를 다음으로 받을 수 있다
// String message = result.getResponse().getContentAsString(Charset.forName("UTF-8"))
Assertions.assertThat(HttpStatus.BAD_REQUEST);
Assertions.assertThat(message).contains("직업은 필수입니다"
, "직업은 필수입니다");
}
}
결과
message = Validation failed for argument [0] in public void kr.sample.demo.demo202008.Test202008Controller.registMember(kr.sample.demo.demo202008.RequestRegistMember) with 2 errors: [Field error in object 'requestRegistMember' on field 'age': rejected value [9]; codes [Min.requestRegistMember.age,Min.age,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [requestRegistMember.age,age]; arguments []; default message [age],20]; default message [20살 이후부터 가입 가능합니다]] [Field error in object 'requestRegistMember' on field 'jobName': rejected value [null]; codes [NotBlank.requestRegistMember.jobName,NotBlank.jobName,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [requestRegistMember.jobName,jobName]; arguments []; default message [jobName]]; default message [직업은 필수입니다]] |
다만 코드에서도 확인할 수 있듯 resolvedException을 통해 메세지를 확인할 수 있다. HttpStatus 는 400 에러로 발생. 메세지는 내가 의도한대로 나왔으니 어쨋든 테스트는 성공한 샘이다.
그리고 코드내에 주석을 추가했는데, @ControllerAdvice에 있다면 리턴받을때 받는 방식을 바꿀 수 있느니 참조하길 바란다.(만약 @ControllerAdvice로 핸들링하지 않는다면 resolvedException으로만 받을 수 있다)
객체와 Valid를 테스트하고 싶다면 전자를, Http와 같이 테스트하고 싶다면 후자를 추천한다.
끝.
'공부 > 프로그래밍' 카테고리의 다른 글
[springboot] Dynamodb, Local로 연결하여 연동테스트 및 기능살펴보기 (0) | 2020.08.22 |
---|---|
[react] hook 에서 componentDidMount, componentWillUnmount 기능 구현하기 (0) | 2020.08.21 |
[junit5] Mock을 이용한 단위 테스트 (@InjectMocks 과 @Mock 차이) (0) | 2020.08.13 |
[gradle] 외부 jar파일 추가하기 (1) | 2020.08.11 |
[springboot] ControllerAdvice를 이용해 정해진 폼으로 리턴하기 (0) | 2020.08.06 |
댓글