Spring boot

Request Test

Subi 2023. 8. 1. 10:38

Create 기능을 개발하기 위해 Request를 개발했는데

여러가지 어노테이션이 많이 적용되서 이걸 테스트해보고 싶어졌다.

예시로 현재 개발한 DmCodeRequest를 보면

@Getter
@Setter
@NoArgsConstructor(access =  AccessLevel.PROTECTED)
public class DmCodeRequest {

    @Schema(description = "DM 코드" ,example = "string")
    @NotBlank @NotNull
    @Pattern(regexp = "^(?!.*\\s)[A-Za-z0-9@$!%*#?&]+$", message="올바르지 않은 정규식 입니다.")
    @Size(max = 30)
    private String dmCode;

    @Schema(description = "DM 코드명")
    @NotBlank @NotNull
    @Size(max = 30)
    private String dmCodeName;

    @Schema(description = "발송 위치",example="Enum" , implementation = SendLocation.class)
    @EnumValid(enumClass = SendLocation.class)
    private String sendLocation;

    @Schema(description = "상세 내용")
    @Size(max = 200)
    private String details;
}

이러한 형태이다.

  1. dmCode
    • dmCode 는 String 형식으로 문자열을 Request 받는다.
    • 조건은 한글은 허용되지 않고, 영문과 숫자 그리고 특수 문자만 허용되고 길이는 30자를 넘으면 안된다.
    • 정규식은 “^(?!.\s)[A-Za-z0-9@$!%#?&]+$” 형태로 지정을 하였고 MaxSize는 30을 설정 하였다.
  2. dmCodeName
    • dmCodeName 은 String 형식으로 문자열을 Request 받는다.
    • 정규식은 따로 해당되지 않고 문자열에 대한 길이만 30자로 제한이 있다.
  3. sendLocation
  4. details
    • details은 String 형식으로 문자열을 Request 받는다.
    • 정규식은 따로 해당되지 않고 문자열에 대한 길이만 200자로 제한이 있다.

TestCode

  1. dmCode
@Test
@DisplayName("DmCode에 대한 정규식 테스트")
void dmCodeRegularTest(){
    //given
    //정규식 : "^(?!.*\\s)[A-Za-z0-9@$!%*#?&]+$"
    //한글 X / 영문,숫자,특수문자 허용
    String dmCode = "test@한글";
    DmCodeRequest dmCodeRequest = new DmCodeRequest(dmCode, "테스트", "맴버쉽", "디테일 테스트");

    //when
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validate = factory.getValidator();
    Set<ConstraintViolation<DmCodeRequest>> constraintViolations = validate.validate(dmCodeRequest);            //정규식에 위반될 시 정규식에 위반된 객체가 Set으로 담기게 된다

    //then
    assertFalse(constraintViolations.isEmpty());                //정규식에 위반되면 constraintViolations 가 empty가 아니라서 false 반환
}
  • DmCodeRequest 에 대한 DTO를 만든다.
  • ValidatorFactory로 Validation 검사를 해주는 객체를 만든다.
  • ValidatorFactory에 있는 getVaildator를 이용해 validate 객체를 생성한다.
  • 그리고 validate에 있는 메서드 validate로 매게변수로 DmCodeRequest를 담아 유효성 검사를 진행한다.
  • DmCodeRequest가 정규식에 위반 될 시 위반된 객체가 Set에 담기게 된다.
    constraintViolations = 
    [
    ConstraintViolationImpl{interpolatedMessage='올바르지 않은 정규식 입니다.',
     propertyPath=dmCode, 
    rootBeanClass=class com.giantstep.unionapiserver.domain.dmCodeManagement.dto.DmCodeRequest, 
    messageTemplate='올바르지 않은 정규식 입니다.'}
    ]
    
  • ex)
  • 객체를 담은 constaintViolations (Set) 에 대한 빈 값에 대한 체크 isEmpty를 실행시켜 빈 값이면 True, 빈 값이 아닐 시 false (위반된 객체가 담겼기 때문에) 를 retrun 한다.
  • assert.assertFalse로 검사를 진행한다.
  1. dmCodeName
@Test
@DisplayName("DmCodeName 에 최대 사이즈 30에 대한 테스트")
void dmCodeNameMaxSize30Test() {
    //given
    String dmCodeName = "길이가 30자 제한인데 이거를 어떻게 막아야 되는지 검사하는 테스트";   //37자 (공백포함)
    DmCodeRequest dmCodeRequest = new DmCodeRequest("test", dmCodeName, "맴버쉽", "디테일 테스트");

    //when
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validate = factory.getValidator();
    Set<ConstraintViolation<DmCodeRequest>> constraintViolations = validate.validate(dmCodeRequest);

    //then
    assertFalse(constraintViolations.isEmpty());
}
  • 정규식에 대한 기본 프로세스는 똑같다.
  • 위에 dmCode 가 정규식에 대한 검사를 진행했다면 dmCodeName은 MaxSize에 대한 검사를 진행해준다.
  1. details
@Test
@DisplayName("Details 에 최대 사이즈 200에 대한 테스트")
void detailsMaxSize200Test() {
    //given
    String details = "낭비하지 마 네 시간은 은행\\n" +
            "서둘러서 정리해 걔는 real bad\\n" +
            "받아주면 안돼\\n" +
            "No, you better trust me\\n" +
            "답답해서 그래\\n" +
            "저번에도 봤지만 너 없을 때\\n" +
            "걘 여기저기에 눈빛을 뿌리네\\n" +
            "아주 눈부시게\\n" +
            "Honestly 우리 사이에\\n" +
            "He's been totally lyin', yeah\\n" +
            "내 생일 파티에 너만 못 온 그날\\n" +
            "혜진이가 엄청 혼났던 그날\\n" +
            "지원이가 여친이랑 헤어진 그날\\n" +
            "걔는 언제나 네가 없이 그날\\n" +
            "너무 멋있는 옷을 입고 그날\\n" +
            "Heard him say\\n" +
            "We can go wherever you like\\n" +
            "Baby, say the words and I'm down\\n" +
            "All I need is you on my side\\n" +
            "We can go whenever you like\\n" +
            "Now, where are you? (Mm-mhm)\\n" +
            "What's your ETA? What's your ETA? (Mm-mhm-mm)\\n" +
            "What's your ETA? What's your ETA? (Mm-mhm)\\n" +
            "*What's your ETA? What's your ETA?*\\n" +
            "*I'll be there right now, lose that boy on her arm*\\n" +
            "You might also like";   //603자 (공백포함)
    DmCodeRequest dmCodeRequest = new DmCodeRequest("test", "디엠코드네임", "맴버쉽", details);

    //when
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validate = factory.getValidator();
    Set<ConstraintViolation<DmCodeRequest>> constraintViolations = validate.validate(dmCodeRequest);

    //then
    assertFalse(constraintViolations.isEmpty());
}
  • details 또한 MaxSize에 대한 검사를 진행해준다.
  1. sendLocation
@Test
@DisplayName("SendLocation에 대한 Enum에 해당하는 String 값인지 (어노테이션) 테스트")
void sendLocationEnumTest() {
    //given
    String sendLocation = "맴버쉽sdsdsdsds";
    DmCodeRequest dmCodeRequest = new DmCodeRequest("test", "테스트", sendLocation, "디테일 테스트");

    //when
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validate = factory.getValidator();
    Set<ConstraintViolation<DmCodeRequest>> constraintViolations = validate.validate(dmCodeRequest);

    //then
    assertFalse(constraintViolations.isEmpty());
}
  • 정규식에 대한 기본 프로세스는 똑같다.
  • Enum 에 대한 Anotation에서 Enum에 대한 값이 만족하지 않으면 false 과 message를 담아 똑같은 결과가 발생한다.

+추가

Sevice Test를 진행하던 중 같은 Request를 객체로 받아 사용하는데 왜 정규식에서 Error가 발생하지 않을까 라는 의문이 생겼다.

찾아보니, @NotNull 과 같은 Validation Anotation은 자동으로 적용되지 않는다.

Bean Validation Anotation은 일반적으로 Spring MVC 레이어 (ex)@RestController)나 JPA 레이어에서 사용되기 때문에 기본Service Test Code에선 자동으로 수행되지 않는다.

해당 객체에 대한 유효성 검사를 실행할려면 직접 Validator를 사용하여 검증하여야 한다.