LoginSignup
21
26

More than 5 years have passed since last update.

Spring 単項目バリデーションのテスト

Posted at

はじめに

Formクラスなどの単項目バリデーションの動作確認を、Controllerのテストで書いているのを見かけることがあります。Controllerのテストは事前に書くことが多く、テストパターンが多いとテストクラスが大きくなって可読性も悪くなります。

Formクラスのテストとして書けばコード量も減り、テスト内容も明確にすることができます。

以下、Spring Boot 2.0.5 で確認。

テスト対象クラス

以下のUserFormクラスのバリデーションをテストします。

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;

}

バリデーション
各フィールドにアノテーションで以下のバリデーションを実装。

  • userId
    • @NotNull
      • nullを許可しない。
  • userName
    • @Size(max = 2)
      • 最大文字数は2。
    • @NotBlank
      • null、空文字、半角スペースのみ入力を許可しない。

テストクラス

UserFormクラスに対するテストクラスとして作成。

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("劉備");
    }

    /**
     * エラーなし
     */
    @Test
    public void noError() {
        validator.validate(userForm, bindingResult);
        assertThat(bindingResult.getFieldError(), is(nullValue()));
    }

    /**
     * userIdが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"));
    }

    /**
     * userNameのサイズが上限超え
     */
    @Test
    public void userNameSizeIsOverLimit() {
        userForm.setUserName("夏侯惇");
        validator.validate(userForm, bindingResult);
        assertThat(bindingResult.getFieldError().getField(), is("userName"));
        assertThat(bindingResult.getFieldError().getDefaultMessage(), is("size must be between 0 and 2"));
    }

    /**
     * userNameが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が空文字
     */
    @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が半角スペースのみ
     */
    @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"));
    }
}

org.springframework.validation.Validator@Autowiredし、userFormbindingResultvalidateメソッドに渡せば、バリデーションを実行できます。バリデーション結果はbindingResultに入っているので、その中身に対しアサートをかければOKです。

テストメソッドの書き方としては、beforeで正常系の状態を作っておき、各テストメソッドで一部だけ異常系に変更してテストするのが、見た目的にもスッキリしていいかなと思います。

補足

Formクラスで単項バリデーションテストできるからControllerのテストは全くいらないかと言われるとそうではなく、例えばControllerでエラーメッセージの変換をしているとか、そもそもFormクラスにバリデーションがかかっているのか確認したいとかいう時はControllerでテストする必要があります。

ただ網羅的なテストはFormクラスのテストで抑えられるので、Controllerでのテストパターンが減らせることは間違いないです。

21
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
26