forked from DevFW-CICD/spring-petclinic
Refactor the logic and add unit test
-<add>: add `@NotBlank` validation to pet's name. -<refactor>: delete useless code and add unit test to check duplicate Pet name validation logic. -<modify>: add `Id` to pet in unit test. -<refactor>: classify unit test. <modify>: adjust code format.
This commit is contained in:
parent
14af47d4e5
commit
50866def72
3 changed files with 114 additions and 39 deletions
|
@ -17,6 +17,7 @@ package org.springframework.samples.petclinic.model;
|
|||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as
|
||||
|
@ -29,6 +30,7 @@ import jakarta.persistence.MappedSuperclass;
|
|||
public class NamedEntity extends BaseEntity {
|
||||
|
||||
@Column(name = "name")
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
|
|
|
@ -99,45 +99,41 @@ class PetController {
|
|||
}
|
||||
|
||||
@PostMapping("/pets/new")
|
||||
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model,
|
||||
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
if (StringUtils.hasText(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) {
|
||||
|
||||
if (StringUtils.hasText(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null)
|
||||
result.rejectValue("name", "duplicate", "already exists");
|
||||
}
|
||||
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
if (pet.getBirthDate() != null && pet.getBirthDate().isAfter(currentDate)) {
|
||||
result.rejectValue("birthDate", "typeMismatch.birthDate");
|
||||
}
|
||||
|
||||
owner.addPet(pet);
|
||||
if (result.hasErrors()) {
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
owner.addPet(pet);
|
||||
this.owners.save(owner);
|
||||
redirectAttributes.addFlashAttribute("message", "New Pet has been Added");
|
||||
return "redirect:/owners/{ownerId}";
|
||||
}
|
||||
|
||||
@GetMapping("/pets/{petId}/edit")
|
||||
public String initUpdateForm(Owner owner, @PathVariable("petId") int petId, ModelMap model,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
Pet pet = owner.getPet(petId);
|
||||
model.put("pet", pet);
|
||||
public String initUpdateForm(Owner owner, @PathVariable("petId") int petId, RedirectAttributes redirectAttributes) {
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@PostMapping("/pets/{petId}/edit")
|
||||
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model,
|
||||
public String processUpdateForm(Owner owner, @Valid Pet pet, BindingResult result,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
|
||||
String petName = pet.getName();
|
||||
|
||||
// checking if the pet name already exist for the owner
|
||||
if (StringUtils.hasText(petName)) {
|
||||
Pet existingPet = owner.getPet(petName.toLowerCase(), false);
|
||||
Pet existingPet = owner.getPet(petName, false);
|
||||
if (existingPet != null && !existingPet.getId().equals(pet.getId())) {
|
||||
result.rejectValue("name", "duplicate", "already exists");
|
||||
}
|
||||
|
@ -149,7 +145,6 @@ class PetController {
|
|||
}
|
||||
|
||||
if (result.hasErrors()) {
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,12 @@
|
|||
package org.springframework.samples.petclinic.owner;
|
||||
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledInNativeImage;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
|
@ -28,6 +31,10 @@ import org.springframework.context.annotation.FilterType;
|
|||
import org.springframework.test.context.aot.DisabledInAotMode;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
|
@ -62,10 +69,16 @@ class PetControllerTests {
|
|||
cat.setId(3);
|
||||
cat.setName("hamster");
|
||||
given(this.owners.findPetTypes()).willReturn(Lists.newArrayList(cat));
|
||||
|
||||
Owner owner = new Owner();
|
||||
Pet pet = new Pet();
|
||||
Pet dog = new Pet();
|
||||
owner.addPet(pet);
|
||||
owner.addPet(dog);
|
||||
pet.setId(TEST_PET_ID);
|
||||
dog.setId(TEST_PET_ID + 1);
|
||||
pet.setName("petty");
|
||||
dog.setName("doggy");
|
||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(owner);
|
||||
}
|
||||
|
||||
|
@ -87,25 +100,72 @@ class PetControllerTests {
|
|||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormHasErrors() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "type"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "type", "required"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
@Nested
|
||||
class ProcessCreationFormHasErrors {
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormWithBlankName() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "\t \n")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "name"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "name", "required"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormWithDuplicateName() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "petty")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "name"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "name", "duplicate"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormWithMissingPetType() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "type"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "type", "required"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormWithInvalidBirthDate() throws Exception {
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
String futureBirthDate = currentDate.plusMonths(1).toString();
|
||||
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty")
|
||||
.param("birthDate", futureBirthDate))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "birthDate"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "birthDate", "typeMismatch.birthDate"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitUpdateForm() throws Exception {
|
||||
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(model().attributeExists("pet"))
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitUpdateForm() throws Exception {
|
||||
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(model().attributeExists("pet"))
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,15 +178,33 @@ class PetControllerTests {
|
|||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessUpdateFormHasErrors() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty")
|
||||
.param("birthDate", "2015/02/12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
@Nested
|
||||
class ProcessUpdateFormHasErrors {
|
||||
|
||||
@Test
|
||||
void testProcessUpdateFormWithInvalidBirthDate() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", " ")
|
||||
.param("birthDate", "2015/02/12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "birthDate"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "birthDate", "typeMismatch"))
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessUpdateFormWithBlankName() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", " ")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "name"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "name", "required"))
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue