What are the best practices for integration testing in Spring MVC?

Integration testing in Spring MVC verifies that multiple layers of the application — controllers, services, repositories, and configuration — work correctly together, as opposed to unit tests that isolate a single class. Doing this well means realistic tests that don't become slow, flaky, or destructive to shared data.

Key Points: • @SpringBootTest boots the full (or a substantial slice of the) application context so components interact as they would in production. • MockMvc or TestRestTemplate simulates real HTTP requests and lets assertions check status codes, headers, and response bodies end to end. • Use a separate test profile and an isolated database (e.g. an embedded H2 instance or a Testcontainers instance) to avoid touching production or shared dev data. • Clean up test data after each test, typically with @Transactional tests that roll back, or explicit teardown logic, so tests stay independent and repeatable. • Focus integration tests on the interactions between layers — request routing, transaction boundaries, serialization — leaving pure business-logic edge cases to faster unit tests.

Example: A checkout flow integration test might use @SpringBootTest with an embedded H2 database, send a real HTTP POST through TestRestTemplate to place an order, and verify both the response and that the order was actually persisted, with the transaction rolled back afterward.

Code Example:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderIntegrationTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void createsOrder() {
        ResponseEntity<Order> response =
                restTemplate.postForEntity("/orders", new OrderRequest(...), Order.class);

        assertEquals(HttpStatus.CREATED, response.getStatusCode());
    }
}

Interview Tip: A concise interview answer is:

"For Spring MVC integration tests, I use @SpringBootTest with MockMvc or TestRestTemplate to exercise real HTTP flows across controllers, services, and the database. I keep tests isolated with a dedicated test profile and an embedded or containerized database, and roll back or clean up data after each test so runs stay independent."