From e4214237da1cd160ee6ceda7b13e6af1027074ee Mon Sep 17 00:00:00 2001 From: Ralf Ueberfuhr <40685729+ueberfuhr@users.noreply.github.com> Date: Tue, 14 Feb 2023 07:28:13 +0100 Subject: [PATCH] BAEL-6097: Pitfalls on Testing with Spring Boot (#13441) * BAEL-6097: Create project * BAEL-6097: Implement sample code and tests with custom test slices * BAEL-6097: Fix application-test.yml * BAEL-6097: Rename tests to match BDD naming strategy, add test for Mapper Integration Test --- pom.xml | 4 +- .../spring-boot-3-test-pitfalls/pom.xml | 87 +++++++++++++++++++ .../baeldung/sample/pets/PetsApplication.java | 13 +++ .../baeldung/sample/pets/boundary/PetDto.java | 10 +++ .../sample/pets/boundary/PetDtoMapper.java | 13 +++ .../sample/pets/boundary/PetsController.java | 28 ++++++ .../com/baeldung/sample/pets/domain/Pet.java | 4 + .../sample/pets/domain/PetService.java | 14 +++ .../pets/domain/PetServiceRepository.java | 13 +++ .../pets/domain/PetServiceRepositoryImpl.java | 29 +++++++ .../src/main/resources/application.yml | 1 + .../boundary/PetDtoMapperIntegrationTest.java | 47 ++++++++++ .../pets/boundary/PetsBoundaryLayer.java | 10 +++ .../PetsControllerMvcIntegrationTest.java | 36 ++++++++ .../domain/PetServiceIntegrationTest.java | 26 ++++++ .../pets/domain/PetServiceUnitTest.java | 31 +++++++ .../sample/pets/domain/PetsDomainLayer.java | 10 +++ .../sample/test/slices/PetsBoundaryTest.java | 52 +++++++++++ .../sample/test/slices/PetsDomainTest.java | 52 +++++++++++ .../src/test/resources/application-test.yml | 11 +++ 20 files changed, 490 insertions(+), 1 deletion(-) create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/PetsApplication.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDto.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDtoMapper.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetsController.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/Pet.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetService.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepository.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepositoryImpl.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/main/resources/application.yml create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetDtoMapperIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsBoundaryLayer.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsControllerMvcIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceIntegrationTest.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceUnitTest.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetsDomainLayer.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsBoundaryTest.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsDomainTest.java create mode 100644 spring-boot-modules/spring-boot-3-test-pitfalls/src/test/resources/application-test.yml diff --git a/pom.xml b/pom.xml index 4016d669a4..83ba73229f 100644 --- a/pom.xml +++ b/pom.xml @@ -965,6 +965,7 @@ spring-boot-modules/spring-boot-3 spring-boot-modules/spring-boot-3-native spring-boot-modules/spring-boot-3-observation + spring-boot-modules/spring-boot-3-test-pitfalls spring-swagger-codegen/custom-validations-opeanpi-codegen testing-modules/testing-assertions persistence-modules/fauna @@ -1163,6 +1164,7 @@ spring-boot-modules/spring-boot-3 spring-boot-modules/spring-boot-3-native spring-boot-modules/spring-boot-3-observation + spring-boot-modules/spring-boot-3-test-pitfalls spring-swagger-codegen/custom-validations-opeanpi-codegen testing-modules/testing-assertions persistence-modules/fauna @@ -1283,7 +1285,7 @@ 11 - + parents diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml b/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml new file mode 100644 index 0000000000..90e4ba022a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + spring-boot-3-test-pitfalls + 0.0.1-SNAPSHOT + spring-boot-3-test-pitfalls + Demo project for Spring Boot Testing Pitfalls + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.projectlombok + lombok + true + + + org.mapstruct + mapstruct + ${org.mapstruct.version} + true + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + + + + + + + + 1.5.3.Final + 3.0.0-M7 + + + + diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/PetsApplication.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/PetsApplication.java new file mode 100644 index 0000000000..17ba1abb2e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/PetsApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.sample.pets; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PetsApplication { + + public static void main(String[] args) { + SpringApplication.run(PetsApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDto.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDto.java new file mode 100644 index 0000000000..62b1202ce8 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDto.java @@ -0,0 +1,10 @@ +package com.baeldung.sample.pets.boundary; + +import lombok.Data; + +@Data +public class PetDto { + + private String name; + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDtoMapper.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDtoMapper.java new file mode 100644 index 0000000000..07fbb77f2e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetDtoMapper.java @@ -0,0 +1,13 @@ +package com.baeldung.sample.pets.boundary; + +import com.baeldung.sample.pets.domain.Pet; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface PetDtoMapper { + + PetDto map(Pet source); + + Pet map(PetDto source); + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetsController.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetsController.java new file mode 100644 index 0000000000..d95d43028b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/boundary/PetsController.java @@ -0,0 +1,28 @@ +package com.baeldung.sample.pets.boundary; + +import com.baeldung.sample.pets.domain.PetService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collection; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/pets") +@RequiredArgsConstructor +public class PetsController { + + private final PetService service; + private final PetDtoMapper mapper; + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public Collection readAll() { + return service.getPets().stream() + .map(mapper::map) + .collect(Collectors.toList()); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/Pet.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/Pet.java new file mode 100644 index 0000000000..3dfe5e1a47 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/Pet.java @@ -0,0 +1,4 @@ +package com.baeldung.sample.pets.domain; + +public record Pet(String name) { +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetService.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetService.java new file mode 100644 index 0000000000..c5f83047b8 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetService.java @@ -0,0 +1,14 @@ +package com.baeldung.sample.pets.domain; + +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class PetService { + + @Delegate + private final PetServiceRepository repo; + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepository.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepository.java new file mode 100644 index 0000000000..1900f72a1c --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepository.java @@ -0,0 +1,13 @@ +package com.baeldung.sample.pets.domain; + +import java.util.Collection; + +public interface PetServiceRepository { + + boolean add(Pet pet); + + void clear(); + + Collection getPets(); + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepositoryImpl.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepositoryImpl.java new file mode 100644 index 0000000000..d1d4bba175 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/java/com/baeldung/sample/pets/domain/PetServiceRepositoryImpl.java @@ -0,0 +1,29 @@ +package com.baeldung.sample.pets.domain; + +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@Component +public class PetServiceRepositoryImpl implements PetServiceRepository { + + private final Set pets = new HashSet<>(); + + @Override + public Set getPets() { + return Collections.unmodifiableSet(pets); + } + + @Override + public boolean add(Pet pet) { + return this.pets.add(pet); + } + + @Override + public void clear() { + this.pets.clear(); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/resources/application.yml b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/resources/application.yml new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/main/resources/application.yml @@ -0,0 +1 @@ + diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetDtoMapperIntegrationTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetDtoMapperIntegrationTest.java new file mode 100644 index 0000000000..14b12cb6e9 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetDtoMapperIntegrationTest.java @@ -0,0 +1,47 @@ +package com.baeldung.sample.pets.boundary; + +import com.baeldung.sample.pets.domain.PetService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockReset; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +@ExtendWith(SpringExtension.class) +public class PetDtoMapperIntegrationTest { + + @Configuration + @ComponentScan(basePackageClasses = PetDtoMapper.class) + static class PetDtoMapperTestConfig { + + /* + * This would be necessary because the controller is also initialized + * and needs the service, although we do not want to test it here. + * + * Solutions: + * - place the mapper into a separate sub package + * - do not test the mapper separately, test it integrated within the controller + * (recommended) + */ + @Bean + PetService createServiceMock() { + return mock(PetService.class, MockReset.withSettings(MockReset.AFTER)); + } + + } + + @Autowired + PetDtoMapper mapper; + + @Test + void shouldExist() { // simply test correct test setup + assertThat(mapper).isNotNull(); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsBoundaryLayer.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsBoundaryLayer.java new file mode 100644 index 0000000000..2a83b364c3 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsBoundaryLayer.java @@ -0,0 +1,10 @@ +package com.baeldung.sample.pets.boundary; + +import org.springframework.context.annotation.ComponentScan; + +/** + * Just an interface to use for compiler-checked component scanning during tests. + * @see ComponentScan#basePackageClasses() + */ +public interface PetsBoundaryLayer { +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsControllerMvcIntegrationTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsControllerMvcIntegrationTest.java new file mode 100644 index 0000000000..9a5df7b727 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/boundary/PetsControllerMvcIntegrationTest.java @@ -0,0 +1,36 @@ +package com.baeldung.sample.pets.boundary; + +import com.baeldung.sample.pets.domain.PetService; +import com.baeldung.sample.test.slices.PetsBoundaryTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.Collections; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@PetsBoundaryTest +class PetsControllerMvcIntegrationTest { + + @Autowired + MockMvc mvc; + @Autowired + PetService service; + + @Test + void shouldReturnEmptyArrayWhenGetPets() throws Exception { + when(service.getPets()).thenReturn(Collections.emptyList()); + mvc.perform( + get("/pets") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andExpect(content().string("[]")); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceIntegrationTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceIntegrationTest.java new file mode 100644 index 0000000000..5e2ec41089 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceIntegrationTest.java @@ -0,0 +1,26 @@ +package com.baeldung.sample.pets.domain; + +import com.baeldung.sample.test.slices.PetsDomainTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@PetsDomainTest +class PetServiceIntegrationTest { + + @Autowired + PetService service; + @Autowired // Mock + PetServiceRepository repository; + + @Test + void shouldAddPetWhenNotAlreadyExisting() { + var pet = new Pet("Dog"); + when(repository.add(pet)).thenReturn(true); + var result = service.add(pet); + assertThat(result).isTrue(); + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceUnitTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceUnitTest.java new file mode 100644 index 0000000000..b0ecdfaeb7 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetServiceUnitTest.java @@ -0,0 +1,31 @@ +package com.baeldung.sample.pets.domain; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PetServiceUnitTest { + + PetService service = new PetService(new PetServiceRepositoryImpl()); + + @Test + void shouldAddPetWhenNotAlreadyExisting() { + var pet = new Pet("Dog"); + var result = service.add(pet); + assertThat(result).isTrue(); + assertThat(service.getPets()).hasSize(1); + } + + @Test + void shouldNotAddPetWhenAlreadyExisting() { + var pet = new Pet("Cat"); + var result = service.add(pet); + assertThat(result).isTrue(); + // try a second time + result = service.add(pet); + assertThat(result).isFalse(); + assertThat(service.getPets()).hasSize(1); + } + + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetsDomainLayer.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetsDomainLayer.java new file mode 100644 index 0000000000..f32fd189e0 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/pets/domain/PetsDomainLayer.java @@ -0,0 +1,10 @@ +package com.baeldung.sample.pets.domain; + +import org.springframework.context.annotation.ComponentScan; + +/** + * Just an interface to use for compiler-checked component scanning during tests. + * @see ComponentScan#basePackageClasses() + */ +public interface PetsDomainLayer { +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsBoundaryTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsBoundaryTest.java new file mode 100644 index 0000000000..f58239f971 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsBoundaryTest.java @@ -0,0 +1,52 @@ +package com.baeldung.sample.test.slices; + +import com.baeldung.sample.pets.boundary.PetsBoundaryLayer; +import com.baeldung.sample.pets.boundary.PetsController; +import com.baeldung.sample.pets.domain.PetService; +import org.junit.jupiter.api.Tag; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.mock.mockito.MockReset; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ActiveProfiles; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static org.mockito.Mockito.mock; + +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@WebMvcTest(controllers = PetsController.class) +@ComponentScan(basePackageClasses = PetsBoundaryLayer.class) +@Import(PetsBoundaryTest.PetBoundaryTestConfiguration.class) +// further features that can help to configure and execute tests +@ActiveProfiles({ "test", "boundary-test" }) +@Tag("integration-test") +@Tag("boundary-test") +public @interface PetsBoundaryTest { + + @TestConfiguration + class PetBoundaryTestConfiguration { + + @Primary + @Bean + PetService createPetServiceMock() { + return mock( + PetService.class, + MockReset.withSettings(MockReset.AFTER) + ); + } + + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsDomainTest.java b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsDomainTest.java new file mode 100644 index 0000000000..b061889135 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/java/com/baeldung/sample/test/slices/PetsDomainTest.java @@ -0,0 +1,52 @@ +package com.baeldung.sample.test.slices; + +import com.baeldung.sample.pets.domain.PetServiceRepository; +import com.baeldung.sample.pets.domain.PetsDomainLayer; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.test.mock.mockito.MockReset; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static org.mockito.Mockito.mock; + +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@ExtendWith(SpringExtension.class) +@ComponentScan(basePackageClasses = PetsDomainLayer.class) +@Import(PetsDomainTest.PetServiceTestConfiguration.class) +// further features that can help to configure and execute tests +@ActiveProfiles({"test", "domain-test"}) +@Tag("integration-test") +@Tag("domain-test") +public @interface PetsDomainTest { + + @TestConfiguration + class PetServiceTestConfiguration { + + @Primary + @Bean + PetServiceRepository createPetsRepositoryMock() { + return mock( + PetServiceRepository.class, + MockReset.withSettings(MockReset.AFTER) + ); + } + + } + +} diff --git a/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/resources/application-test.yml b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/resources/application-test.yml new file mode 100644 index 0000000000..9801fe9e7e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-test-pitfalls/src/test/resources/application-test.yml @@ -0,0 +1,11 @@ +logging: + level: + root: info + org: + springframework: + test: + context: + cache: DEBUG +spring: + main: + allow-bean-definition-overriding: true