From cc757a959b01826ac8942184616c1169b3feef73 Mon Sep 17 00:00:00 2001 From: OwenYang Date: Mon, 1 Feb 2021 00:38:55 +0800 Subject: [PATCH 1/2] add spring validation dependency --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 56c2598..214b1e5 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.boot:spring-boot-starter-validation' testImplementation('org.springframework.boot:spring-boot-starter-test') { // Vintage provide a way for junit5 to test junit4 From 0cba8b59e328e52cebb4e610ec37fd1cf57a694f Mon Sep 17 00:00:00 2001 From: OwenYang Date: Mon, 1 Feb 2021 00:39:25 +0800 Subject: [PATCH 2/2] issue-129: as a developer , i would like to validate my input add usercontroller , User object and integration test for UserController --- .../tdd/controller/UserController.java | 38 ++++++++++ .../java/com/ordestiny/tdd/model/User.java | 23 ++++++ .../tdd/controller/UserControllerTest.java | 72 +++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 src/main/java/com/ordestiny/tdd/controller/UserController.java create mode 100644 src/main/java/com/ordestiny/tdd/model/User.java create mode 100644 src/test/java/com/ordestiny/tdd/controller/UserControllerTest.java diff --git a/src/main/java/com/ordestiny/tdd/controller/UserController.java b/src/main/java/com/ordestiny/tdd/controller/UserController.java new file mode 100644 index 0000000..f3f7bd5 --- /dev/null +++ b/src/main/java/com/ordestiny/tdd/controller/UserController.java @@ -0,0 +1,38 @@ +package com.ordestiny.tdd.controller; + +import com.ordestiny.tdd.model.User; +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Map; + +@RestController +@AllArgsConstructor +public class UserController { + + @PostMapping("/user") + ResponseEntity addUser(@Valid @RequestBody User user) { + return new ResponseEntity<>(user, HttpStatus.OK); + } + + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException.class) + public Map handleValidationExceptions( + MethodArgumentNotValidException ex) { + Map errors = new HashMap<>(); + ex.getBindingResult().getAllErrors().forEach((error) -> { + String fieldName = ((FieldError) error).getField(); + String errorMessage = error.getDefaultMessage(); + errors.put(fieldName, errorMessage); + }); + return errors; + } + +} diff --git a/src/main/java/com/ordestiny/tdd/model/User.java b/src/main/java/com/ordestiny/tdd/model/User.java new file mode 100644 index 0000000..6be02d7 --- /dev/null +++ b/src/main/java/com/ordestiny/tdd/model/User.java @@ -0,0 +1,23 @@ +package com.ordestiny.tdd.model; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +@Getter +@Setter +public class User { + @NotBlank(message = "name is mandatory") + private String name; + + @Pattern(regexp = "M|F", flags = Pattern.Flag.CASE_INSENSITIVE) + private String sex; + + @Pattern(regexp="^[A-Za-z0-9+_.-]+@(.+)$") + private String email; + + @Pattern(regexp="(^$|[0-9]{10})") + private String phone; +} diff --git a/src/test/java/com/ordestiny/tdd/controller/UserControllerTest.java b/src/test/java/com/ordestiny/tdd/controller/UserControllerTest.java new file mode 100644 index 0000000..a09265a --- /dev/null +++ b/src/test/java/com/ordestiny/tdd/controller/UserControllerTest.java @@ -0,0 +1,72 @@ +package com.ordestiny.tdd.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ordestiny.tdd.model.User; +import org.hamcrest.core.Is; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(MockitoExtension.class) +class UserControllerTest { + + @InjectMocks + UserController controller; + + MockMvc mockMvc; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void addUser_illegalInput_expect4xx() throws Exception { + User user = new User(); + user.setEmail("testgmail.com"); + user.setPhone("DDDD"); + user.setSex("Boy"); + + ObjectMapper mapper = new ObjectMapper(); + String userObject = mapper.writeValueAsString(user); + + mockMvc.perform(MockMvcRequestBuilders.post("/user").contentType(MediaType.APPLICATION_JSON).content(userObject)) + .andExpect(status().isBadRequest()) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", Is.is("name is mandatory"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.phone", Is.is("must match \"(^$|[0-9]{10})\""))) + .andExpect(MockMvcResultMatchers.jsonPath("$.email", Is.is("must match \"^[A-Za-z0-9+_.-]+@(.+)$\""))) + .andExpect(MockMvcResultMatchers.jsonPath("$.sex", Is.is("must match \"M|F\""))) + .andExpect(MockMvcResultMatchers.content() + .contentType(MediaType.APPLICATION_JSON)); + } + + @Test + void addUser_legalInput_expect200AndSuccess() throws Exception { + User user = new User(); + user.setEmail("test@gmail.com"); + user.setPhone("0911111111"); + user.setSex("F"); + user.setName("owen"); + + ObjectMapper mapper = new ObjectMapper(); + String userObject = mapper.writeValueAsString(user); + + mockMvc.perform(MockMvcRequestBuilders.post("/user").contentType(MediaType.APPLICATION_JSON).content(userObject)) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", Is.is(user.getName()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.phone", Is.is(user.getPhone()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.email", Is.is(user.getEmail()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.sex", Is.is(user.getSex()))) + .andExpect(MockMvcResultMatchers.content() + .contentType(MediaType.APPLICATION_JSON)); + } +} \ No newline at end of file