agentskills.codes
SP

spring-boot-test-patterns

Provides comprehensive testing patterns for Spring Boot applications including unit, integration, slice, and container-based testing with JUnit 5, Mockito, Testcontainers, and performance optimization. Use when implementing robust test suites for Spring Boot applications.

Install

mkdir -p .claude/skills/spring-boot-test-patterns && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15755" && unzip -o skill.zip -d .claude/skills/spring-boot-test-patterns && rm skill.zip

Installs to .claude/skills/spring-boot-test-patterns

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Provides comprehensive testing patterns for Spring Boot applications including unit, integration, slice, and container-based testing with JUnit 5, Mockito, Testcontainers, and performance optimization. Use when implementing robust test suites for Spring Boot applications.
272 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)

About this skill

Spring Boot Testing Patterns

Overview

This skill provides comprehensive guidance for writing robust test suites for Spring Boot applications. It covers unit testing with Mockito, integration testing with Testcontainers, performance-optimized slice testing patterns, and best practices for maintaining fast feedback loops.

When to Use This Skill

Use this skill when:

  • Writing unit tests for services, repositories, or utilities
  • Implementing integration tests with real databases using Testcontainers
  • Setting up performance-optimized test slices (@DataJpaTest, @WebMvcTest)
  • Configuring Spring Boot 3.5+ @ServiceConnection for container management
  • Testing REST APIs with MockMvc, TestRestTemplate, or WebTestClient
  • Optimizing test performance through context caching and container reuse
  • Setting up CI/CD pipelines for integration tests
  • Implementing comprehensive test strategies for monolithic or microservices applications

Core Concepts

Test Architecture Philosophy

Spring Boot testing follows a layered approach with distinct test types:

1. Unit Tests

  • Fast, isolated tests without Spring context
  • Use Mockito for dependency injection
  • Focus on business logic validation
  • Target completion time: < 50ms per test

2. Slice Tests

  • Minimal Spring context loading for specific layers
  • Use @DataJpaTest for repository tests
  • Use @WebMvcTest for controller tests
  • Use @WebFluxTest for reactive controller tests
  • Target completion time: < 100ms per test

3. Integration Tests

  • Full Spring context with real dependencies
  • Use @SpringBootTest with @ServiceConnection containers
  • Test complete application flows
  • Target completion time: < 500ms per test

Key Testing Annotations

Spring Boot Test Annotations:

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

Testcontainer Annotations:

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

Dependencies

Maven Dependencies

<dependencies>
    <!-- Spring Boot Test Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- Testcontainers -->
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>1.19.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>postgresql</artifactId>
        <version>1.19.0</version>
        <scope>test</scope>
    </dependency>

    <!-- Additional Testing Dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

Gradle Dependencies

dependencies {
    // Spring Boot Test Starter
    testImplementation("org.springframework.boot:spring-boot-starter-test")

    // Testcontainers
    testImplementation("org.testcontainers:junit-jupiter:1.19.0")
    testImplementation("org.testcontainers:postgresql:1.19.0")

    // Additional Dependencies
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.boot:spring-boot-starter-web")
}

Instructions

Unit Testing Pattern

Test business logic with mocked dependencies:

class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void shouldFindUserByIdWhenExists() {
        // Arrange
        Long userId = 1L;
        User user = new User();
        user.setId(userId);
        user.setEmail("[email protected]");

        when(userRepository.findById(userId)).thenReturn(Optional.of(user));

        // Act
        Optional<User> result = userService.findById(userId);

        // Assert
        assertThat(result).isPresent();
        assertThat(result.get().getEmail()).isEqualTo("[email protected]");
        verify(userRepository, times(1)).findById(userId);
    }
}

Slice Testing Pattern

Use focused test slices for specific layers:

// Repository test with minimal context
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestContainerConfig
public class UserRepositoryIntegrationTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldSaveAndRetrieveUserFromDatabase() {
        // Arrange
        User user = new User();
        user.setEmail("[email protected]");
        user.setName("Test User");

        // Act
        User saved = userRepository.save(user);
        userRepository.flush();

        Optional<User> retrieved = userRepository.findByEmail("[email protected]");

        // Assert
        assertThat(retrieved).isPresent();
        assertThat(retrieved.get().getName()).isEqualTo("Test User");
    }
}

REST API Testing Pattern

Test controllers with MockMvc for faster execution:

@SpringBootTest
@AutoConfigureMockMvc
@Transactional
public class UserControllerIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private UserService userService;

    @Test
    void shouldCreateUserAndReturn201() throws Exception {
        User user = new User();
        user.setEmail("[email protected]");
        user.setName("New User");

        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(user)))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id").exists())
            .andExpect(jsonPath("$.email").value("[email protected]"))
            .andExpect(jsonPath("$.name").value("New User"));
    }
}

Testcontainers with @ServiceConnection

Configure containers with Spring Boot 3.5+:

@TestConfiguration
public class TestContainerConfig {

    @Bean
    @ServiceConnection
    public PostgreSQLContainer<?> postgresContainer() {
        return new PostgreSQLContainer<>(DockerImageName.parse("postgres:16-alpine"))
            .withDatabaseName("testdb")
            .withUsername("test")
            .withPassword("test");
    }
}

Examples

Basic Unit Test

@Test
void shouldCalculateTotalPrice() {
    // Arrange
    OrderItem item1 = new OrderItem();
    item1.setPrice(10.0);
    item1.setQuantity(2);

    OrderItem item2 = new OrderItem();
    item2.setPrice(15.0);
    item2.setQuantity(1);

    List<OrderItem> items = List.of(item1, item2);

    // Act
    double total = orderService.calculateTotal(items);

    // Assert
    assertThat(total).isEqualTo(35.0);
}

Integration Test with Testcontainers

@SpringBootTest
@TestContainerConfig
public class OrderServiceIntegrationTest {

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserRepository userRepository;

    @MockBean
    private PaymentService paymentService;

    @Test
    void shouldCreateOrderWithRealDatabase() {
        // Arrange
        User user = new User();
        user.setEmail("[email protected]");
        user.setName("John Doe");
        User savedUser = userRepository.save(user);

        OrderRequest request = new OrderRequest();
        request.setUserId(savedUser.getId());
        request.setItems(List.of(
            new OrderItemRequest(1L, 2),
            new OrderItemRequest(2L, 1)
        ));

        when(paymentService.processPayment(any())).thenReturn(true);

        // Act
        OrderResponse response = orderService.createOrder(request);

        // Assert
        assertThat(response.getOrderId()).isNotNull();
        assertThat(response.getStatus()).isEqualTo("COMPLETED");
        verify(paymentService, times(1)).processPayment(any());
    }
}

Reactive Test Pattern

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebTestClient
public class ReactiveUserControllerIntegrationTest {

    @Autowired
    private WebTestClient webTestClient;

    @Test
    void shouldReturnUserAsJsonReactive() {
        // Arrange
        User user = new User();
        user.setEmail("[email protected]");
        user.setName("Reactive User");

        // Act & Assert
        webTestClient.get()
            .uri("/api/users/1")
            .exchange()
            .expectStatus().isOk()
            .expectBody()
            .jsonPath("$.email").isEqualTo("[email protected]")
            .jsonPath("$.name").isEqualTo("Reactive User");
    }
}

Best Practices

1. Choose the Right Test Type

Select appropriate test annotations based on scope:

// Use @DataJpaTest for repository-only tests (fastest)
@DataJpaTest
public class UserRepositoryTest { }

// Use @WebMvcTest for controller-only tests
@WebMvcTest(UserController.class)
public class UserControllerTest { }

// Use @SpringBootTest only for full integration testing
@SpringBootTest
public class UserServiceFullIntegrationTest { }

2. Use @ServiceConnection for Container Management

Prefer @ServiceConnection over manual @DynamicPropertySource for cleaner code:

// Good - Spring Boot 3.5+
@TestConfiguration


---

*Content truncated.*

Search skills

Search the agent skills registry