diff --git a/datajpatest/pom.xml b/datajpatest/pom.xml index b06b907..98580d8 100644 --- a/datajpatest/pom.xml +++ b/datajpatest/pom.xml @@ -29,7 +29,17 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-maven-plugin + 2.5.3 + + + org.hibernate.validator + hibernate-validator + 6.2.0.Final + javax.validation validation-api @@ -76,6 +86,12 @@ 1.4.200 test + + org.spockframework + spock-core + RELEASE + test + diff --git a/datajpatest/src/main/java/com/example/datajpatest/controller/MemberController.java b/datajpatest/src/main/java/com/example/datajpatest/controller/MemberController.java index 1ee297b..f34c566 100644 --- a/datajpatest/src/main/java/com/example/datajpatest/controller/MemberController.java +++ b/datajpatest/src/main/java/com/example/datajpatest/controller/MemberController.java @@ -7,6 +7,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import javax.validation.Valid; import java.net.URI; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; @@ -22,7 +23,7 @@ public MemberController(MemberRepository memberRepository) { } @PostMapping("/member") - public ResponseEntity joinMember(@RequestBody MemberJoinRequest request) { + public ResponseEntity joinMember(@Valid @RequestBody MemberJoinRequest request) { MemberJpaEntity entity = MemberJpaEntity.from(request); MemberJpaEntity saved = memberRepository.save(entity); final Long memberId = saved.getId(); diff --git a/datajpatest/src/main/java/com/example/datajpatest/controller/MemberJoinRequest.java b/datajpatest/src/main/java/com/example/datajpatest/controller/MemberJoinRequest.java index a88cb44..84d675c 100644 --- a/datajpatest/src/main/java/com/example/datajpatest/controller/MemberJoinRequest.java +++ b/datajpatest/src/main/java/com/example/datajpatest/controller/MemberJoinRequest.java @@ -2,17 +2,21 @@ import com.example.datajpatest.model.Member; import lombok.Getter; +import lombok.Setter; -import java.beans.ConstructorProperties; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; @Getter +@Setter public class MemberJoinRequest implements Member { - private final Long id; - private final String name; + @NotNull + private Long id; + @NotBlank + private String name; + @NotNull + @Pattern(regexp = "[0-9]{10}|[0-9]{3}-[0-9]{2}-[0-9]{5}", message = "10자리의 숫자 또는 대시를 포함한 12자리의 숫자만 입력가능합니다.") + private String businessNumber; - @ConstructorProperties({"id", "name"}) - public MemberJoinRequest(Long id, String name) { - this.id = id; - this.name = name; - } } diff --git a/datajpatest/src/test/java/com/example/datajpatest/controller/MemberJoinRequestSpec.groovy b/datajpatest/src/test/java/com/example/datajpatest/controller/MemberJoinRequestSpec.groovy new file mode 100644 index 0000000..8635a86 --- /dev/null +++ b/datajpatest/src/test/java/com/example/datajpatest/controller/MemberJoinRequestSpec.groovy @@ -0,0 +1,114 @@ +package com.example.datajpatest.controller + +import spock.lang.Shared +import spock.lang.Specification +import spock.lang.Subject +import spock.lang.Unroll + +import javax.validation.ConstraintViolation +import javax.validation.Validation +import javax.validation.Validator +import javax.validation.ValidatorFactory + +class MemberJoinRequestSpec extends Specification { + + @Subject + private MemberJoinRequest sut + + @Shared + private Validator validator + + def setupSpec() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory() + validator = factory.getValidator() + } + + def setup() { + sut = getNoConstraintValidationMemberJoinRequest() + } + + @Unroll + def "사업자 등록번호가 #testBusinessNumber 를 허용한다."() { + given: + sut.setBusinessNumber(testBusinessNumber) + + when: + Set> constraintViolations = validator.validate(sut) + + then: + noConstraintViolation(constraintViolations) + + where: + testBusinessNumber << ['1448125784', '144-81-25784'] + } + + def "사업자 등록번호는 null 을 허용하지 않는다."() { + given: + sut.setBusinessNumber(null) + + when: + Set> constraintViolations = validator.validate(sut) + + then: + constraintViolations.size() == 1 + with(constraintViolations[0]) { + propertyPath.toString() == 'businessNumber' + invalidValue == null + messageTemplate == '{javax.validation.constraints.NotNull.message}' + } + } + + @Unroll + def "사업자 등록번호는 #testBusinessNumber.length() 자리를 허용하지 않는다."() { + given: + sut.setBusinessNumber(testBusinessNumber) + + when: + Set> constraintViolations = validator.validate(sut) + + then: + constraintViolations.size() == 1 + with(constraintViolations[0]) { + propertyPath.toString() == 'businessNumber' + invalidValue.toString() == testBusinessNumber + message == '10자리의 숫자 또는 대시를 포함한 12자리의 숫자만 입력가능합니다.' + } + + where: + testBusinessNumber << ['', '1', '123456789', '12345678901', '1234567890123', '12345678901234'] + } + + @Unroll + def "사업자 등록번호는 문자열 #testBusinessNumber (#testBusinessNumber.length()) 을 허용하지 않는다."() { + given: + sut.setBusinessNumber(testBusinessNumber) + + when: + Set> constraintViolations = validator.validate(sut) + + then: + constraintViolations.size() == 1 + with(constraintViolations[0]) { + propertyPath.toString() == 'businessNumber' + invalidValue.toString() == testBusinessNumber + message == '10자리의 숫자 또는 대시를 포함한 12자리의 숫자만 입력가능합니다.' + } + + where: + testBusinessNumber << ['apple', 'tablelands'] + } + + + static def getNoConstraintValidationMemberJoinRequest() { + def req = new MemberJoinRequest() + req.id = 1 + req.name = "테스터" + req.businessNumber = "1234567890" + return req + } + + static def noConstraintViolation(Set> constraintViolations) { + constraintViolations.isEmpty() + } + +}