Skip to content
Spring Boot sb testing 3 min read

Testing in Spring Boot

Tests are how you keep a Spring Boot application changeable without fear. Spring Boot ships a rich testing toolkit out of the box and a layered set of test slices that let you load only the part of the application context a given test needs. This section walks from plain JUnit 5 up to full end-to-end tests with Testcontainers.

The testing pyramid

A healthy suite has many fast, isolated tests at the bottom and a few slow, realistic ones at the top. Spring Boot maps cleanly onto this shape.

LayerWhat it testsSpring involvementSpeed
UnitOne class in isolationNone — plain JUnit + MockitoMilliseconds
SliceOne layer (web, JPA, JSON)Partial contextFast
IntegrationWired components togetherFull / large contextSlower
End-to-endReal HTTP + real DBFull context + TestcontainersSlowest

Tip: Write the bulk of your logic so it can be covered by unit tests with no Spring context at all. Reserve @SpringBootTest for the handful of paths that genuinely need the whole application wired together.

spring-boot-starter-test

A single starter brings in everything you need. It is added with test scope by Spring Initializr.

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

That one line bundles the libraries you reach for constantly:

LibraryPurpose
JUnit 5 (Jupiter)The test engine — @Test, lifecycle, assertions
Spring Test & Spring Boot Test@SpringBootTest, slices, MockMvc, TestRestTemplate
AssertJFluent assertThat(...) assertions
MockitoMocking and stubbing collaborators
HamcrestMatcher library (used by MockMvc jsonPath)
JSONassert / JsonPathAsserting on JSON documents
AwaitilityTesting asynchronous code

Unit vs slice vs integration

A unit test instantiates one class directly and mocks its collaborators. No Spring context starts, so it runs in milliseconds.

class PriceCalculatorTest {
    @Test
    void appliesTenPercentDiscount() {
        var calculator = new PriceCalculator();
        assertThat(calculator.discounted(100, 10)).isEqualTo(90);
    }
}

A slice test boots a narrow, auto-configured part of the context. @WebMvcTest loads the MVC layer but not your repositories; @DataJpaTest loads JPA and an embedded database but not your controllers. This is faster and more focused than a full context.

An integration test with @SpringBootTest starts the entire application context — every bean, configuration, and auto-configuration — optionally on a real HTTP port. Use it when interaction between layers is the thing under test.

Test slices overview

Each slice is a composed annotation that disables full auto-configuration and enables only what its layer needs. They keep tests fast and intent obvious.

SliceLoadsTypical use
@WebMvcTestControllers, filters, MockMvcTesting REST endpoints
@DataJpaTestJPA, repositories, embedded DBTesting queries
@JsonTestJackson/Gson serializationVerifying JSON mapping
@RestClientTestRestClient/RestTemplate + mock serverTesting HTTP clients
@DataMongoTestSpring Data MongoDBTesting Mongo repositories
@WebFluxTestWebFlux controllers + WebTestClientReactive endpoints

Note: Inside a slice you replace the layers you did not load with mocks. In a @WebMvcTest you supply the service layer with @MockitoBean — the Spring Boot 3.4+ replacement for the deprecated @MockBean.

A first runnable test

The Spring Initializr always generates one context-load test. If it passes, your beans wire together correctly.

@SpringBootTest
class ApplicationTests {

    @Test
    void contextLoads() {
        // Fails if any bean cannot be created
    }
}

Run it with Maven:

./mvnw test

Output:

[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS

In This Section

Last updated June 13, 2026
Was this helpful?