diff --git a/pom.xml b/pom.xml index 9b9b815df..dd9eddd9b 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,4 @@ - + 4.0.0 @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent 3.4.0 - + org.springframework.samples @@ -17,15 +17,14 @@ - + 17 UTF-8 UTF-8 - + 2024-11-28T14:37:52Z - + 1.0.1 5.3.3 4.7.0 @@ -41,7 +40,7 @@ - + org.springframework.boot spring-boot-starter-actuator @@ -72,12 +71,12 @@ test - + io.projectreactor reactor-core - + com.h2database h2 @@ -94,7 +93,7 @@ runtime - + javax.cache cache-api @@ -104,7 +103,7 @@ caffeine - + org.webjars webjars-locator-lite @@ -233,8 +232,7 @@ spring-boot-maven-plugin - + build-info @@ -269,8 +267,7 @@ - + io.github.git-commit-id git-commit-id-maven-plugin @@ -279,15 +276,14 @@ false - + - + org.cyclonedx cyclonedx-maven-plugin - + org.pitestpitest-maven1.15.0org.pitestpitest-junit5-plugin1.2.1XMLfalsetrue @@ -347,7 +343,7 @@ unpack - + generate-resources @@ -374,7 +370,7 @@ - + compile @@ -395,8 +391,7 @@ - + org.eclipse.m2e lifecycle-mapping @@ -414,7 +409,7 @@ - + @@ -427,7 +422,7 @@ - + @@ -440,7 +435,7 @@ - + @@ -452,4 +447,4 @@ - + \ No newline at end of file diff --git a/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java b/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java index 426ca5c24..049b21ba9 100644 --- a/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java @@ -14,240 +14,248 @@ * limitations under the License. */ -package org.springframework.samples.petclinic.owner; + package org.springframework.samples.petclinic.owner; -import org.assertj.core.util.Lists; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledInNativeImage; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.test.context.aot.DisabledInAotMode; -import org.springframework.test.context.bean.override.mockito.MockitoBean; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - -import java.time.LocalDate; -import java.util.Optional; - -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -/** - * Test class for {@link OwnerController} - * - * @author Colin But - * @author Wick Dynex - */ -@WebMvcTest(OwnerController.class) -@DisabledInNativeImage -@DisabledInAotMode -class OwnerControllerTests { - - private static final int TEST_OWNER_ID = 1; - - @Autowired - private MockMvc mockMvc; - - @MockitoBean - private OwnerRepository owners; - - private Owner george() { - Owner george = new Owner(); - george.setId(TEST_OWNER_ID); - george.setFirstName("George"); - george.setLastName("Franklin"); - george.setAddress("110 W. Liberty St."); - george.setCity("Madison"); - george.setTelephone("6085551023"); - Pet max = new Pet(); - PetType dog = new PetType(); - dog.setName("dog"); - max.setType(dog); - max.setName("Max"); - max.setBirthDate(LocalDate.now()); - george.addPet(max); - max.setId(1); - return george; - } - - @BeforeEach - void setup() { - - Owner george = george(); - given(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))) - .willReturn(new PageImpl<>(Lists.newArrayList(george))); - - given(this.owners.findAll(any(Pageable.class))).willReturn(new PageImpl<>(Lists.newArrayList(george))); - - given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(george)); - Visit visit = new Visit(); - visit.setDate(LocalDate.now()); - george.getPet("Max").getVisits().add(visit); - - } - - @Test - void testInitCreationForm() throws Exception { - mockMvc.perform(get("/owners/new")) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("owner")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } - - @Test - void testProcessCreationFormSuccess() throws Exception { - mockMvc - .perform(post("/owners/new").param("firstName", "Joe") - .param("lastName", "Bloggs") - .param("address", "123 Caramel Street") - .param("city", "London") - .param("telephone", "1316761638")) - .andExpect(status().is3xxRedirection()); - } - - @Test - void testProcessCreationFormHasErrors() throws Exception { - mockMvc - .perform(post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London")) - .andExpect(status().isOk()) - .andExpect(model().attributeHasErrors("owner")) - .andExpect(model().attributeHasFieldErrors("owner", "address")) - .andExpect(model().attributeHasFieldErrors("owner", "telephone")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } - - @Test - void testInitFindForm() throws Exception { - mockMvc.perform(get("/owners/find")) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("owner")) - .andExpect(view().name("owners/findOwners")); - } - - @Test - void testProcessFindFormSuccess() throws Exception { - Page tasks = new PageImpl<>(Lists.newArrayList(george(), new Owner())); - when(this.owners.findByLastNameStartingWith(anyString(), any(Pageable.class))).thenReturn(tasks); - mockMvc.perform(get("/owners?page=1")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList")); - } - - @Test - void testProcessFindFormByLastName() throws Exception { - Page tasks = new PageImpl<>(Lists.newArrayList(george())); - when(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))).thenReturn(tasks); - mockMvc.perform(get("/owners?page=1").param("lastName", "Franklin")) - .andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); - } - - @Test - void testProcessFindFormNoOwnersFound() throws Exception { - Page tasks = new PageImpl<>(Lists.newArrayList()); - when(this.owners.findByLastNameStartingWith(eq("Unknown Surname"), any(Pageable.class))).thenReturn(tasks); - mockMvc.perform(get("/owners?page=1").param("lastName", "Unknown Surname")) - .andExpect(status().isOk()) - .andExpect(model().attributeHasFieldErrors("owner", "lastName")) - .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) - .andExpect(view().name("owners/findOwners")); - - } - - @Test - void testInitUpdateOwnerForm() throws Exception { - mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("owner")) - .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) - .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) - .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) - .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) - .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } - - @Test - void testProcessUpdateOwnerFormSuccess() throws Exception { - mockMvc - .perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") - .param("lastName", "Bloggs") - .param("address", "123 Caramel Street") - .param("city", "London") - .param("telephone", "1616291589")) - .andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } - - @Test - void testProcessUpdateOwnerFormUnchangedSuccess() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)) - .andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } - - @Test - void testProcessUpdateOwnerFormHasErrors() throws Exception { - mockMvc - .perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") - .param("lastName", "Bloggs") - .param("address", "") - .param("telephone", "")) - .andExpect(status().isOk()) - .andExpect(model().attributeHasErrors("owner")) - .andExpect(model().attributeHasFieldErrors("owner", "address")) - .andExpect(model().attributeHasFieldErrors("owner", "telephone")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } - - @Test - void testShowOwner() throws Exception { - mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)) - .andExpect(status().isOk()) - .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) - .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) - .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) - .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) - .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) - .andExpect(model().attribute("owner", hasProperty("pets", not(empty())))) - .andExpect(model().attribute("owner", - hasProperty("pets", hasItem(hasProperty("visits", hasSize(greaterThan(0))))))) - .andExpect(view().name("owners/ownerDetails")); - } - - @Test - public void testProcessUpdateOwnerFormWithIdMismatch() throws Exception { - int pathOwnerId = 1; - - Owner owner = new Owner(); - owner.setId(2); - owner.setFirstName("John"); - owner.setLastName("Doe"); - owner.setAddress("Center Street"); - owner.setCity("New York"); - owner.setTelephone("0123456789"); - - when(owners.findById(pathOwnerId)).thenReturn(Optional.of(owner)); - - mockMvc.perform(MockMvcRequestBuilders.post("/owners/{ownerId}/edit", pathOwnerId).flashAttr("owner", owner)) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/owners/" + pathOwnerId + "/edit")) - .andExpect(flash().attributeExists("error")); - } - -} + import org.assertj.core.util.Lists; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + import org.junit.jupiter.api.condition.DisabledInNativeImage; + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; + import org.springframework.data.domain.Page; + import org.springframework.data.domain.PageImpl; + import org.springframework.data.domain.Pageable; + import org.springframework.test.context.aot.DisabledInAotMode; + import org.springframework.test.context.bean.override.mockito.MockitoBean; + import org.springframework.test.web.servlet.MockMvc; + import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + + import java.time.LocalDate; + import java.util.Optional; + + import static org.hamcrest.Matchers.empty; + import static org.hamcrest.Matchers.greaterThan; + import static org.hamcrest.Matchers.hasItem; + import static org.hamcrest.Matchers.hasProperty; + import static org.hamcrest.Matchers.hasSize; + import static org.hamcrest.Matchers.is; + import static org.hamcrest.Matchers.not; + import static org.junit.jupiter.api.Assertions.assertNull; + import static org.mockito.ArgumentMatchers.any; + import static org.mockito.ArgumentMatchers.anyString; + import static org.mockito.ArgumentMatchers.eq; + import static org.mockito.BDDMockito.given; + import static org.mockito.Mockito.when; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; + import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + + /** + * Test class for {@link OwnerController} + * + * Authors: Colin But, Wick Dynex + */ + @WebMvcTest(OwnerController.class) + @DisabledInNativeImage + @DisabledInAotMode + class OwnerControllerTests { + + private static final int TEST_OWNER_ID = 1; + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private OwnerRepository owners; + + private Owner george() { + Owner george = new Owner(); + george.setId(TEST_OWNER_ID); + george.setFirstName("George"); + george.setLastName("Franklin"); + george.setAddress("110 W. Liberty St."); + george.setCity("Madison"); + george.setTelephone("6085551023"); + Pet max = new Pet(); + PetType dog = new PetType(); + dog.setName("dog"); + max.setType(dog); + max.setName("Max"); + max.setBirthDate(LocalDate.now()); + george.addPet(max); + max.setId(1); + return george; + } + + @BeforeEach + void setup() { + + Owner george = george(); + given(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))) + .willReturn(new PageImpl<>(Lists.newArrayList(george))); + + given(this.owners.findAll(any(Pageable.class))).willReturn(new PageImpl<>(Lists.newArrayList(george))); + + given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(george)); + Visit visit = new Visit(); + visit.setDate(LocalDate.now()); + george.getPet("Max").getVisits().add(visit); + + // Added assertion to cover the branch where the pet is not found + assertNull(george.getPet("NonExistent"), "Expected getPet to return null when pet is not found"); + } + + @Test + void testInitCreationForm() throws Exception { + mockMvc.perform(get("/owners/new")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("owner")) + .andExpect(view().name("owners/createOrUpdateOwnerForm")); + } + + @Test + void testProcessCreationFormSuccess() throws Exception { + mockMvc + .perform(post("/owners/new").param("firstName", "Joe") + .param("lastName", "Bloggs") + .param("address", "123 Caramel Street") + .param("city", "London") + .param("telephone", "1316761638")) + .andExpect(status().is3xxRedirection()); + } + + @Test + void testProcessCreationFormHasErrors() throws Exception { + mockMvc + .perform(post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London")) + .andExpect(status().isOk()) + .andExpect(model().attributeHasErrors("owner")) + .andExpect(model().attributeHasFieldErrors("owner", "address")) + .andExpect(model().attributeHasFieldErrors("owner", "telephone")) + .andExpect(view().name("owners/createOrUpdateOwnerForm")); + } + + @Test + void testInitFindForm() throws Exception { + mockMvc.perform(get("/owners/find")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("owner")) + .andExpect(view().name("owners/findOwners")); + } + + @Test + void testProcessFindFormSuccess() throws Exception { + Page tasks = new PageImpl<>(Lists.newArrayList(george(), new Owner())); + when(this.owners.findByLastNameStartingWith(anyString(), any(Pageable.class))).thenReturn(tasks); + mockMvc.perform(get("/owners?page=1")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList")); + } + + @Test + void testProcessFindFormByLastName() throws Exception { + Page tasks = new PageImpl<>(Lists.newArrayList(george())); + when(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))).thenReturn(tasks); + mockMvc.perform(get("/owners?page=1").param("lastName", "Franklin")) + .andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); + } + + @Test + void testProcessFindFormNoOwnersFound() throws Exception { + Page tasks = new PageImpl<>(Lists.newArrayList()); + when(this.owners.findByLastNameStartingWith(eq("Unknown Surname"), any(Pageable.class))).thenReturn(tasks); + mockMvc.perform(get("/owners?page=1").param("lastName", "Unknown Surname")) + .andExpect(status().isOk()) + .andExpect(model().attributeHasFieldErrors("owner", "lastName")) + .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) + .andExpect(view().name("owners/findOwners")); + + } + + @Test + void testInitUpdateOwnerForm() throws Exception { + mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("owner")) + .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) + .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) + .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) + .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) + .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) + .andExpect(view().name("owners/createOrUpdateOwnerForm")); + } + + @Test + void testProcessUpdateOwnerFormSuccess() throws Exception { + mockMvc + .perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") + .param("lastName", "Bloggs") + .param("address", "123 Caramel Street") + .param("city", "London") + .param("telephone", "1616291589")) + .andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/{ownerId}")); + } + + @Test + void testProcessUpdateOwnerFormUnchangedSuccess() throws Exception { + mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)) + .andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/{ownerId}")); + } + + @Test + void testProcessUpdateOwnerFormHasErrors() throws Exception { + mockMvc + .perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") + .param("lastName", "Bloggs") + .param("address", "") + .param("telephone", "")) + .andExpect(status().isOk()) + .andExpect(model().attributeHasErrors("owner")) + .andExpect(model().attributeHasFieldErrors("owner", "address")) + .andExpect(model().attributeHasFieldErrors("owner", "telephone")) + .andExpect(view().name("owners/createOrUpdateOwnerForm")); + } + + @Test + void testShowOwner() throws Exception { + mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)) + .andExpect(status().isOk()) + .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) + .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) + .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) + .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) + .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) + .andExpect(model().attribute("owner", hasProperty("pets", not(empty())))) + .andExpect(model().attribute("owner", + hasProperty("pets", hasItem(hasProperty("visits", hasSize(greaterThan(0))))))) + .andExpect(view().name("owners/ownerDetails")) + .andExpect(result -> { + Owner owner = (Owner) result.getModelAndView().getModel().get("owner"); + // New assertion to exercise the negative branch of getPet + assertNull(owner.getPet("NonExistent"), "Expected getPet to return null when pet is not found"); + }); + } + + @Test + public void testProcessUpdateOwnerFormWithIdMismatch() throws Exception { + int pathOwnerId = 1; + + Owner owner = new Owner(); + owner.setId(2); + owner.setFirstName("John"); + owner.setLastName("Doe"); + owner.setAddress("Center Street"); + owner.setCity("New York"); + owner.setTelephone("0123456789"); + + when(owners.findById(pathOwnerId)).thenReturn(Optional.of(owner)); + + mockMvc.perform(MockMvcRequestBuilders.post("/owners/{ownerId}/edit", pathOwnerId).flashAttr("owner", owner)) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/owners/" + pathOwnerId + "/edit")) + .andExpect(flash().attributeExists("error")); + } + + } + \ No newline at end of file