[JAVA] Spring single item validation test

Introduction

You may see the operation check of single item validation such as Form class written in the test of Controller. The Controller test is often written in advance, and if there are many test patterns, the test class will be large and readability will be poor.

Writing as a test of the Form class reduces the amount of code and makes the test content clear.

Below, confirmed with Spring Boot 2.0.5.

Tested class

Test the validation of the following ʻUserForm` class.

import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Data
public class UserForm {

    @NotNull
    private Integer userId;

    @Size(max = 2)
    @NotBlank
    private String userName;

}

** Validation ** Implement the following validation with annotations in each field.

Test class

Created as a test class for the ʻUserForm` class.

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserFormTest {

    @Autowired
    Validator validator;

    private UserForm userForm = new UserForm();
    private BindingResult bindingResult = new BindException(userForm, "UserForm");

    @Before
    public void before() {
        userForm.setUserId(1);
        userForm.setUserName("Ryu-bi");
    }

    /**
     *No error
     */
    @Test
    public void noError() {
        validator.validate(userForm, bindingResult);
        assertThat(bindingResult.getFieldError(), is(nullValue()));
    }

    /**
     *userId is null
     */
    @Test
    public void userIdIsNull() {
        userForm.setUserId(null);
        validator.validate(userForm, bindingResult);
        assertThat(bindingResult.getFieldError().getField(), is("userId"));
        assertThat(bindingResult.getFieldError().getDefaultMessage(), is("must not be null"));
    }

    /**
     *The size of userName exceeds the upper limit
     */
    @Test
    public void userNameSizeIsOverLimit() {
        userForm.setUserName("Xiahou Dun");
        validator.validate(userForm, bindingResult);
        assertThat(bindingResult.getFieldError().getField(), is("userName"));
        assertThat(bindingResult.getFieldError().getDefaultMessage(), is("size must be between 0 and 2"));
    }

    /**
     *userName is null
     */
    @Test
    public void userNameIsNull() {
        userForm.setUserName(null);
        validator.validate(userForm, bindingResult);
        assertThat(bindingResult.getFieldError().getField(), is("userName"));
        assertThat(bindingResult.getFieldError().getDefaultMessage(), is("must not be blank"));
    }

    /**
     *userName is an empty string
     */
    @Test
    public void userNameIsBlank() {
        userForm.setUserName("");
        validator.validate(userForm, bindingResult);
        assertThat(bindingResult.getFieldError().getField(), is("userName"));
        assertThat(bindingResult.getFieldError().getDefaultMessage(), is("must not be blank"));
    }

    /**
     *userName is only a half-width space
     */
    @Test
    public void userNameIsOnlySpace() {
        userForm.setUserName("  ");
        validator.validate(userForm, bindingResult);
        assertThat(bindingResult.getFieldError().getField(), is("userName"));
        assertThat(bindingResult.getFieldError().getDefaultMessage(), is("must not be blank"));
    }
}

You can perform validation by passing ʻorg.springframework.validation.Validator to @Autowired and ʻuserForm and bindingResult to the validate method. The validation result is in bindingResult, so you can assert the contents.

As for how to write a test method, I think that it is good for the purpose of seeing to create a normal system state with before and change only a part to an abnormal system with each test method and test it. ..

Supplement

When asked if the Controller test is not needed at all because the Form class can perform unary validation tests, for example, the Controller is converting error messages, or the Form class is validated in the first place. If you want to check if it is, you need to test with Controller.

However, since exhaustive tests can be suppressed by tests of the Form class, there is no doubt that the test patterns in Controller can be reduced.

Recommended Posts

Spring single item validation test
Form class validation test with Spring Boot
Self-made Validation with Spring
[JUnit 5] Write a validation test with Spring Boot! [Parameterization test]
Spring validation and error code
Spring Security usage memo test
Spring Boot validation message changes
How to unit test Spring AOP
Write test code in Spring Boot
Get validation results with Spring Boot
Use DBUnit for Spring Boot test
Test Spring framework controller with Junit
About error when implementing spring validation