Claude
Skills
Sign in
Back

spring-boot-test

Included with Lifetime
$97 forever

Spring Boot testing fundamentals including @SpringBootTest, slice tests, MockMvc, mocking with @MockBean, test configuration, and testing utilities. For integration tests with Testcontainers, see spring-boot-integration. USE WHEN: user mentions "spring boot test", "mockmvc", "@WebMvcTest", "@DataJpaTest", asks about "@SpringBootTest", "@MockBean", "spring test", "controller test", "repository test" DO NOT USE FOR: Unit tests - use `junit` with Mockito; Integration tests with real DB - use `spring-boot-integration`; REST API clients - use `rest-assured`; E2E tests - use Selenium

Backend & APIs

What this skill does

# Spring Boot Testing

> **Deep Knowledge**: Use `mcp__documentation__fetch_docs` with technology: `spring-boot-test` for comprehensive documentation.

## When NOT to Use This Skill

- **Pure Unit Tests** - Use `junit` with Mockito for faster tests without Spring context
- **Integration Tests with Real Database** - Use `spring-boot-integration` with Testcontainers
- **REST API Client Testing** - Use `rest-assured` for HTTP testing
- **E2E Web Testing** - Use Selenium or Playwright
- **Microservice Contract Testing** - Use Spring Cloud Contract

## Dependencies

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
```

Includes: JUnit 5, Mockito, AssertJ, Hamcrest, JSONPath, Spring Test

## Test Annotations

### @SpringBootTest - Full Context

```java
@SpringBootTest
class ApplicationTest {
    @Autowired
    private UserService userService;

    @Test
    void contextLoads() {
        assertThat(userService).isNotNull();
    }
}

// With web environment
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class WebApplicationTest {
    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void healthCheck() {
        ResponseEntity<String> response = restTemplate
            .getForEntity("/actuator/health", String.class);
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }
}
```

### Slice Tests (Faster, Focused)

| Annotation | Layer | Auto-configured |
|------------|-------|-----------------|
| `@WebMvcTest` | Controllers | MockMvc, Jackson |
| `@DataJpaTest` | JPA Repositories | TestEntityManager, DataSource |
| `@DataMongoTest` | MongoDB | MongoTemplate |
| `@JsonTest` | JSON serialization | JacksonTester |
| `@RestClientTest` | REST clients | MockRestServiceServer |

```java
// Controller test - only loads web layer
@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void getUser_ReturnsUser() throws Exception {
        when(userService.findById(1L))
            .thenReturn(Optional.of(new User(1L, "John")));

        mockMvc.perform(get("/api/users/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.name").value("John"));
    }
}

// Repository test - uses embedded database
@DataJpaTest
class UserRepositoryTest {

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private UserRepository repository;

    @Test
    void findByEmail_ReturnsUser() {
        User user = new User("[email protected]", "Test User");
        entityManager.persistAndFlush(user);

        Optional<User> found = repository.findByEmail("[email protected]");

        assertThat(found).isPresent()
            .hasValueSatisfying(u -> assertThat(u.getName()).isEqualTo("Test User"));
    }
}
```

## MockMvc

### Basic Requests

```java
@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    // GET request
    @Test
    void getUsers() throws Exception {
        when(userService.findAll()).thenReturn(List.of(
            new User(1L, "Alice"),
            new User(2L, "Bob")
        ));

        mockMvc.perform(get("/api/users")
                .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON))
            .andExpect(jsonPath("$", hasSize(2)))
            .andExpect(jsonPath("$[0].name").value("Alice"));
    }

    // POST request with JSON body
    @Test
    void createUser() throws Exception {
        CreateUserRequest request = new CreateUserRequest("John", "[email protected]");
        User createdUser = new User(1L, "John", "[email protected]");

        when(userService.create(any())).thenReturn(createdUser);

        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content("""
                    {
                        "name": "John",
                        "email": "[email protected]"
                    }
                    """))
            .andExpect(status().isCreated())
            .andExpect(header().exists("Location"))
            .andExpect(jsonPath("$.id").value(1));
    }

    // PUT request
    @Test
    void updateUser() throws Exception {
        mockMvc.perform(put("/api/users/{id}", 1)
                .contentType(MediaType.APPLICATION_JSON)
                .content("""
                    {"name": "Updated Name"}
                    """))
            .andExpect(status().isOk());

        verify(userService).update(eq(1L), any());
    }

    // DELETE request
    @Test
    void deleteUser() throws Exception {
        mockMvc.perform(delete("/api/users/{id}", 1))
            .andExpect(status().isNoContent());

        verify(userService).delete(1L);
    }
}
```

### With Authentication

```java
@WebMvcTest(AdminController.class)
@Import(SecurityConfig.class)
class AdminControllerTest {

    @Autowired
    private MockMvc mockMvc;

    // Using @WithMockUser
    @Test
    @WithMockUser(roles = "ADMIN")
    void adminEndpoint_WithAdminRole_Succeeds() throws Exception {
        mockMvc.perform(get("/api/admin/dashboard"))
            .andExpect(status().isOk());
    }

    @Test
    @WithMockUser(roles = "USER")
    void adminEndpoint_WithUserRole_Forbidden() throws Exception {
        mockMvc.perform(get("/api/admin/dashboard"))
            .andExpect(status().isForbidden());
    }

    // Using JWT token
    @Test
    void withJwtToken() throws Exception {
        String token = jwtTokenProvider.createToken("admin", List.of("ROLE_ADMIN"));

        mockMvc.perform(get("/api/admin/dashboard")
                .header("Authorization", "Bearer " + token))
            .andExpect(status().isOk());
    }
}
```

## Mocking

### @MockBean

```java
@SpringBootTest
class OrderServiceTest {

    @Autowired
    private OrderService orderService;

    @MockBean  // Replaces bean in context with mock
    private PaymentGateway paymentGateway;

    @MockBean
    private InventoryService inventoryService;

    @Test
    void placeOrder_WhenPaymentSucceeds_CreatesOrder() {
        when(inventoryService.checkStock(any())).thenReturn(true);
        when(paymentGateway.charge(any())).thenReturn(PaymentResult.success());

        Order order = orderService.placeOrder(new OrderRequest(...));

        assertThat(order.getStatus()).isEqualTo(OrderStatus.CONFIRMED);
        verify(paymentGateway).charge(any());
    }

    @Test
    void placeOrder_WhenPaymentFails_ThrowsException() {
        when(paymentGateway.charge(any()))
            .thenThrow(new PaymentException("Card declined"));

        assertThatThrownBy(() -> orderService.placeOrder(new OrderRequest(...)))
            .isInstanceOf(PaymentException.class)
            .hasMessage("Card declined");
    }
}
```

### @SpyBean

```java
@SpringBootTest
class NotificationServiceTest {

    @Autowired
    private NotificationService notificationService;

    @SpyBean  // Wraps real bean, allows partial mocking
    private EmailSender emailSender;

    @Test
    void sendNotification_CallsEmailSender() {
        notificationService.notify(user, "Hello");

        verify(emailSender).send(eq(user.getEmail()), any());
    }

    @Test
    void sendNotification_WhenEmailFails_LogsError() {
        doThrow(new EmailException("SMTP error"))
            .when(emailSender).send(any(), any());

        // Method should handle exception gracefully
        assertThatCode(() -> notificationService.notify(user, "Hello"))
            .doesNotThrowAnyException();
    }
}
```

## Test Configuration

### Test Properties

```java
@SpringBootTest
@TestPropertySource(properties = {
    "app.feature.enabled=true",

Related in Backend & APIs