PluginBench
Skill
Review
Audit score 70

spring-boot-test-patterns

giuseppe-trisciuoglio/developer-kit

Comprehensive testing patterns for Spring Boot with JUnit 5, Mockito, Testcontainers, and slice testing.

What is spring-boot-test-patterns?

Provides guidance for writing robust test suites across unit, integration, slice, and container-based testing in Spring Boot applications. Use when writing tests, configuring @Test methods, mocking with @MockBean, or implementing test suites with JUnit 5 and Testcontainers.

  • Unit testing with Mockito and @ExtendWith(MockitoExtension.class) for isolated business logic
  • Slice testing with @DataJpaTest, @WebMvcTest, @WebFluxTest for focused layer testing
  • REST API testing with MockMvc and controller assertions
  • Testcontainers integration with @ServiceConnection for real database/broker containers in Spring Boot 3.5+
  • Performance-optimized test architecture with context caching and reuse strategies
  • CI/CD configuration patterns for automated testing in GitHub Actions

How to install spring-boot-test-patterns

npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill spring-boot-test-patterns
Prerequisites
  • Spring Boot 2.7+ (3.5+ recommended for @ServiceConnection)
  • JUnit 5 (included in spring-boot-starter-test)
  • Mockito (included in spring-boot-starter-test)
  • Docker installed for Testcontainers
  • Maven or Gradle build tool
Claude Code
Cursor
Windsurf
Cline

How to use spring-boot-test-patterns

  1. 1.Add spring-boot-starter-test and testcontainers dependencies to pom.xml or build.gradle
  2. 2.Create unit tests using @ExtendWith(MockitoExtension.class) with @Mock and @InjectMocks for isolated logic
  3. 3.Create slice tests with @DataJpaTest, @WebMvcTest, or @WebFluxTest for specific layers
  4. 4.Configure Testcontainers with @ServiceConnection in a @TestConfiguration class
  5. 5.Apply @Import(TestContainerConfig.class) to test classes requiring containers
  6. 6.Run tests with ./mvnw test and verify container startup in logs
  7. 7.Set up GitHub Actions workflow with Docker service for CI/CD automation

Use cases

Good for
  • Writing unit tests for services and repositories with mocked dependencies
  • Testing REST API endpoints with MockMvc and status/JSON assertions
  • Implementing integration tests with real PostgreSQL or other containers via Testcontainers
  • Testing JPA repositories with @DataJpaTest and real database schemas
  • Setting up automated test suites in CI/CD pipelines with Docker support
Who it's for
  • Spring Boot developers writing test suites
  • QA engineers implementing integration tests
  • Backend developers testing REST APIs and data layers
  • Teams adopting Testcontainers for containerized testing

spring-boot-test-patterns FAQ

When should I use @SpringBootTest vs slice tests like @DataJpaTest?

Use @DataJpaTest, @WebMvcTest, or @WebFluxTest for focused layer testing (< 100ms). Reserve @SpringBootTest only for full integration tests requiring the complete application context (< 500ms). Slice tests are faster due to minimal context loading.

What is @ServiceConnection and when should I use it?

@ServiceConnection automatically wires Testcontainer instances to Spring Boot properties in Spring Boot 3.5+. It replaces manual @DynamicPropertySource configuration, providing cleaner container management. Use it for PostgreSQL, MySQL, RabbitMQ, and other supported containers.

How do I avoid slow test execution with Testcontainers?

Reuse containers at JVM level with withReuse(true) and set TESTCONTAINERS_REUSE_ENABLE=true environment variable. Avoid @DirtiesContext which forces context rebuilds. Group tests by layer to maximize context caching. Keep unit tests under 50ms, slice tests under 100ms.

Should I mock external services or use real containers?

Mock external services in unit tests for speed. Use real containers (Testcontainers) only for integration tests where you need to verify actual database behavior. This balances test speed with confidence in real-world scenarios.

How do I test REST API endpoints?

Use @WebMvcTest(YourController.class) to load only the MVC layer. Inject MockMvc and perform requests with mockMvc.perform(get("/api/path")). Assert on status codes and JSON responses using andExpect(status().isOk()) and jsonPath() matchers.

Full instructions (SKILL.md)

Source of truth, from giuseppe-trisciuoglio/developer-kit.


name: spring-boot-test-patterns description: Provides comprehensive testing patterns for Spring Boot applications covering unit, integration, slice, and container-based testing with JUnit 5, Mockito, Testcontainers, and performance optimization. Use when writing tests, @Test methods, @MockBean mocks, or implementing test suites for Spring Boot applications. allowed-tools: Read, Write, Edit, Bash, Glob, Grep

Spring Boot Testing Patterns

Overview

Comprehensive guidance for writing robust test suites for Spring Boot applications using JUnit 5, Mockito, Testcontainers, and performance-optimized slice testing patterns.

When to Use

  • Writing unit tests for services or repositories with mocked dependencies
  • Implementing integration tests with real databases via Testcontainers
  • Testing REST APIs with @WebMvcTest or MockMvc
  • Configuring @ServiceConnection for container management in Spring Boot 3.5+

Quick Reference

Test TypeAnnotationTarget TimeUse Case
Unit Tests@ExtendWith(MockitoExtension.class)< 50msBusiness logic without Spring context
Repository Tests@DataJpaTest< 100msDatabase operations with minimal context
Controller Tests@WebMvcTest / @WebFluxTest< 100msREST API layer testing
Integration Tests@SpringBootTest< 500msFull application context with containers
Testcontainers@ServiceConnection / @TestcontainersVariesReal database/message broker containers

Core Concepts

Test Architecture Philosophy

  1. Unit Tests — Fast, isolated tests without Spring context (< 50ms)
  2. Slice Tests — Minimal Spring context for specific layers (< 100ms)
  3. Integration Tests — Full Spring context with real dependencies (< 500ms)

Key Annotations

Spring Boot Test:

  • @SpringBootTest — Full application context (use sparingly)
  • @DataJpaTest — JPA components only (repositories, entities)
  • @WebMvcTest — MVC layer only (controllers, @ControllerAdvice)
  • @WebFluxTest — WebFlux layer only (reactive controllers)
  • @JsonTest — JSON serialization components only

Testcontainers:

  • @ServiceConnection — Wire Testcontainer to Spring Boot (3.5+)
  • @DynamicPropertySource — Register dynamic properties at runtime
  • @Testcontainers — Enable Testcontainers lifecycle management

Instructions

1. Unit Testing Pattern

Test business logic with mocked dependencies:

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void shouldFindUserByIdWhenExists() {
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));
        Optional<User> result = userService.findById(1L);
        assertThat(result).isPresent();
        verify(userRepository).findById(1L);
    }
}

See unit-testing.md for advanced patterns.

2. Slice Testing Pattern

Use focused test slices for specific layers:

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestContainerConfig
class UserRepositoryIntegrationTest {
    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldSaveAndRetrieveUser() {
        User saved = userRepository.save(user);
        assertThat(userRepository.findByEmail("test@example.com")).isPresent();
    }
}

See slice-testing.md for all slice patterns.

3. REST API Testing Pattern

Test controllers with MockMvc:

@WebMvcTest(UserController.class)
class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void shouldGetUserById() throws Exception {
        mockMvc.perform(get("/api/users/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.email").value("test@example.com"));
    }
}

4. Testcontainers with @ServiceConnection

Configure containers with Spring Boot 3.5+:

@TestConfiguration
public class TestContainerConfig {
    @Bean
    @ServiceConnection
    public PostgreSQLContainer<?> postgresContainer() {
        return new PostgreSQLContainer<>("postgres:16-alpine");
    }
}

Apply with @Import(TestContainerConfig.class) on test classes. See testcontainers-setup.md for detailed configuration.

5. Add Dependencies

Include required testing dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>1.19.0</version>
    <scope>test</scope>
</dependency>

See test-dependencies.md for complete dependency list.

6. Configure CI/CD

Set up GitHub Actions for automated testing:

name: Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      docker:
        image: docker:20-dind
    steps:
    - uses: actions/checkout@v4
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        distribution: 'temurin'
    - name: Run tests
      run: ./mvnw test

See ci-cd-configuration.md for full CI/CD patterns.

Validation Checkpoints

After implementing tests, verify:

  • Container running: docker ps (look for testcontainer images)
  • Context loaded: check startup logs for "Started Application in X.XX seconds"
  • Test isolation: run tests individually and confirm no cross-contamination

Examples

Full Integration Test with @ServiceConnection

@SpringBootTest
@Import(TestContainerConfig.class)
class OrderServiceIntegrationTest {

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldCreateOrderForExistingUser() {
        User user = userRepository.save(User.builder()
            .email("order-test@example.com")
            .build());

        Order order = orderService.createOrder(user.getId(), List.of(
            new OrderItem("SKU-001", 2)
        ));

        assertThat(order.getId()).isNotNull();
        assertThat(order.getStatus()).isEqualTo(OrderStatus.PENDING);
    }
}

@DataJpaTest with Real Database

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestContainerConfig
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldFindByEmail() {
        userRepository.save(User.builder()
            .email("jpa-test@example.com")
            .build());
        assertThat(userRepository.findByEmail("jpa-test@example.com"))
            .isPresent();
    }
}

See workflow-patterns.md for complete end-to-end examples.

Best Practices

  • Use the right test type: @DataJpaTest for repositories, @WebMvcTest for controllers, @SpringBootTest only for full integration
  • Prefer @ServiceConnection on Spring Boot 3.5+ for cleaner container management over @DynamicPropertySource
  • Keep tests deterministic: Initialize all test data explicitly in @BeforeEach
  • Organize by layer: Group tests by layer to maximize context caching
  • Reuse Testcontainers at JVM level (withReuse(true) + TESTCONTAINERS_REUSE_ENABLE=true)
  • Avoid @DirtiesContext: Forces context rebuild, significantly hurts performance
  • Mock external services, use real databases only when necessary
  • Performance targets: Unit < 50ms, Slice < 100ms, Integration < 500ms

Constraints and Warnings

  • Never use @DirtiesContext unless absolutely necessary (forces context rebuild)
  • Avoid mixing @MockBean with different configurations (creates separate contexts)
  • Testcontainers require Docker; ensure CI/CD pipelines have Docker support
  • Do not rely on test execution order; each test must be independent
  • Be cautious with @TestPropertySource (creates separate contexts)
  • Do not use @SpringBootTest for unit tests; use plain Mockito instead
  • Context caching can be invalidated by different @MockBean configurations
  • Avoid static mutable state in tests (causes flaky tests)

References