티스토리 뷰

ETC

bean validation tutorial

서보민 2018. 3. 12. 19:11

bean-validation

환경

  • MACOS
  • JAVA 9
  • gradle 4.6
  • maven 3.5.3

설치

gradle, maven

$ brew update && brew upgrade && brew cleanup

$ brew install gradle
$ brew install maven

bean-validation 이란?

  • 데이터를 검증하기 위한 Java 표준 기술
  • 검증규칙은 Annotaion으로 사용
  • 데이터의 검증은 Runtime시에 이루어 짐
  • 애노테이션을 이용하여 bean 유효성 검사를 위한 Java API 스펙

Intellij에서 프로젝트 생성

새 프로젝트 생성

Gradle -> Java를 선택 후 next

GroupId와 ArtifactId, Version를 원하는 형식으로 작성 후 next

Gradle home에 gradle이 설치된 경로 (gradle/version/libexec까지 선택) 작성 후 next

build.gradle 파일에 자신이 원하는 maven을 작성

compile, testCompile등은 search.maven에서 원하는 maven을 검색 후 gradle에 맞는 형식을 작성후 dependencies 하위 목록에 작성

build.gradle에 작성을 완료후 Import Changes를 선택

그후 projectname/src/main/java/ 하위에 원하는 코드를 작성한다.


예제

이 튜토리얼에서는 간단한 계정 클래스를 만든다.

필드 값으로는 UUID id, String username, String name, String email이 있고 생성자와 getter를 작성 id는 UUID.randomUUID()로 랜덤값이 생성한다.

코드 작성 시 필드 값에 대해 어노테이션으로 조건을 지정할 수 있다.

어노테이션 정보를 간략하게 설명하면 다음과 같다.

  • @NotNull - 값이 Null인지 확인하고, 반드시 값이 들어가야한다.
  • @NotBlank - null, "", " "를 허용하지 않는다.
  • @Size - size를 지정할 수 있다. 속성으로 Min Max 등을 가진다.
  • @Email - email형식이 맞는지 확인한다. @Email은 3월12이 현재 버그가 발견돼 밑의 코드처럼 정규표현식과 함께 사용
  • @AssertTrue - true 검증
  • @NotEmpty - null이나 size가 0 검증 (String, Collection)
  • @NotBlank - null이나 whitespace 검증 (String)
  • @Positive, @PositiveOrZero - 숫자 검증
  • @Negative, @NegativeOrZero - 숫자 검증
  • @Past, @PastOrPresent - 날짜 검증
  • @Future, @FutureOrPresent - 날짜 검증

JunitTest/src/main/java/io/wisoft/tutorial/domain/Account

package io.wisoft.tutorial.domain;

import javax.validation.constraints.*;
import java.util.UUID;

public class Account {
  @NotNull
  private UUID id;

  @NotBlank(message = "username may not be empty.")
  @Size(min = 4,max = 10, message = "username must be between 4 and 10 characters long.")
  private String username;

  @Size(min=4, max=20, message = "name must be between 4 and 20 characters long.")
  @NotBlank(message = "name may not be empty.")
  private String name;

  @Email(regexp ="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.(?:[a-zA-Z]{2,6})$", message = "Email must be a well-formed email address")
  @NotBlank(message = "비어있지 않다.")
  private String email;

  public Account(){}

  Account(String username, String name, String email) {
    this.id = UUID.randomUUID();

    this.username = username;
    this.name = name;
    this.email = email;
  }

  public UUID getId() {
    return id;
  }

  public String getUsername() {
    return username;
  }

  public String getName() {
    return name;
  }

  public String getEmail() {
    return email;
  }

}

당연히 테스트 코드는 projectname/src/test/ 하위에 작성된다.

.junitTest/src/test/io/wisoft/tutorial/domain/AccountTest

package io.wisoft.tutorial.domain;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Nested;

import javax.validation.ConstraintViolation;
import java.util.List;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

@DisplayName("The account validator test case")
class AccountTest {
  private Account account;


  @org.junit.jupiter.api.Nested
  @DisplayName("Account ID test case")
  class IdValidation {

    @Test
    @DisplayName("정상적인 Account ID")
    void checkIdValidationSuccess() {

      account = new Account("bomin","BoMin Seo", "tjqh55@gmail.com");

      assertNotNull(account);
      assertThat(account.getId()).isNotNull();
    }
  }

  @org.junit.jupiter.api.Nested
  @DisplayName("Account username test case")
  class UsernameValidation{

    @Test
    @DisplayName("정상적인 Username")
    void checkUsernameValidationSuccess(){
      account = new Account("bomin","BoMin Seo","tjqh55@gmail.com");

      final Set<ConstraintViolation<Account>> result =
          SimpleBeanValidator.getViolationsOfCheckValidate(account);

      assertThat(account.getUsername()).isEqualTo("bomin");
      assertThat(result.isEmpty()).isTrue();
    }

    @Test
    @DisplayName("username must be between 4 and 10 characters long.")
    void checkUsernameValidationSuccessFail(){
      account = new Account("bom","BoMin Seo","tjqh55@gmail.com");

      final String result =
          SimpleBeanValidator.getMessageOfCheckValidate(account);

      assertThat(result).contains("username must be between 4 and 10 characters long.");

    }

    @Test
    @DisplayName("Username is blank, username may not be empty.")
    void checkUsernameBlankValidationFail() {
      account = new Account("","bomin Seo", "tjqh55@gmail.com");

      final List<String> result =
          SimpleBeanValidator.getMessageListOfCheckValidate(account);

      assertThat(result.contains("username may not be empty.")).isTrue();
      assertThat(result.contains("username must be between 4 and 10 characters long.")).isTrue();

    }

  }

}

위 테스트 코드에서 SimpleBeanValidator는 코드의 중복성을 배제하기 위헤 따로 빼서 작성한 부분이다.

.junitTest/src/test/io/wisoft/tutorial/domain/SimpleBeanValidator


package io.wisoft.tutorial.domain;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class SimpleBeanValidator {
  private final static ValidatorFactory VALIDATOR_FACTORY = Validation.buildDefaultValidatorFactory();
  private final static Validator VALIDATOR = VALIDATOR_FACTORY.getValidator();

  public static <T> String getMessageOfCheckValidate(final @NotNull T t){
  // 메세지가 1개 일때 사용
    final Set<ConstraintViolation<T>> violations = VALIDATOR.validate(t);
    String result = null;
    for (ConstraintViolation<T> violation : violations) {
      result = violation.getMessage();
    }
    return result;
  }

  public static <T> List<String> getMessageListOfCheckValidate(final @NotNull T t){
  // 메세지가 2개 이상일때 List를 사용 (Blank, Size)
    final Set<ConstraintViolation<T>> violations = VALIDATOR.validate(t);


    final List<String> result =new ArrayList<>();
    for (ConstraintViolation<T> violation : violations) {
      result.add(violation.getMessage());
    }
    return result;
  }

  public static <T> Set<ConstraintViolation<T>> getViolationsOfCheckValidate(final @NotNull T t){
  // 하나의 값일 때 사용
    return VALIDATOR.validate(t);
  }
}

.Account.class , AccountTest.class 비교


==========Account.class부분==========

~~~~

public class Account {
  @NotNull    // id필드 값은 Null이 될 수 없다는 조건을 건다.
  private UUID id;

  ~~~~

}

~~~~

========================================

==========AccountTest.class부분==========

class AccountTest {
  private Account account;


  @org.junit.jupiter.api.Nested
  @DisplayName("Account ID test case")
  class IdValidation {

    @Test
    @DisplayName("정상적인 Account ID")
    void checkIdValidationSuccess() {

      account = new Account("bomin","BoMin Seo", "tjqh55@gmail.com");

      assertNotNull(account);  //Account.class에서 id 필드는 Null이 될 수 없다는 조건이 맞는지 확인
      assertThat(account.getId()).isNotNull(); // id 값이 Null인지 아닌지 확인
    }
  }
}
~~~
========================================


'ETC' 카테고리의 다른 글

처음 배우는 스프링 부트 2 리뷰  (0) 2018.11.19
이더리움 미스트 설치  (0) 2018.03.12
gitlab 설치  (0) 2018.03.12
윈도우 다중 원격접속  (0) 2018.03.12
grafana tutorial  (0) 2018.03.12
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함