본문 바로가기
공부/프로그래밍

[springboot] @valid 테스트하기(Controller에 입력되는 객체 테스트)

by demonic_ 2020. 8. 18.
반응형

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와 같이 테스트하고 싶다면 후자를 추천한다.

 

 

 

끝.

 

반응형

댓글