Test every layer — slice tests for the web and data layers with MockMvc and @DataJpaTest, full integration tests with @SpringBootTest, and fake collaborators with @MockBean.
Note: spring-boot-starter-test comes with every Initializr project. It bundles JUnit 5, AssertJ, Mockito, and Spring’s test support — so you already have everything below without adding a dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>When @WebMvcTest: test a controller in isolation — it loads only the web layer (fast), not the database or services. Note: MockMvc sends fake HTTP requests and asserts on the response without starting a real server. Mock the service the controller depends on.
@WebMvcTest(BookController.class)
class BookControllerTest {
@Autowired MockMvc mvc;
@MockBean BookService service; // faked, not real
@Test
void returnsBook() throws Exception {
given(service.find(1L)).willReturn(Optional.of(new Book("Dune")));
mvc.perform(get("/api/books/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.title").value("Dune"));
}
}Why: @MockBean replaces a real bean in the Spring context with a Mockito mock, so you test one class without its dependencies doing real work. Note: in Spring Boot 3.4+ the same idea is spelled @MockitoBean — both stub behavior with given(...) / when(...).
@SpringBootTest
class OrderServiceTest {
@Autowired OrderService orders;
@MockBean PaymentGateway gateway; // real bean swapped for a mock
@Test
void chargesOnce() {
given(gateway.charge(anyDouble())).willReturn(true);
orders.checkout(...);
verify(gateway).charge(29.99); // assert the interaction
}
}When @DataJpaTest: test repositories against a real (in-memory) database — it loads only the JPA layer and rolls back after each test, so tests stay isolated. Note: this is the "JPA Test" slice; it auto-configures an embedded H2 database for you.
@DataJpaTest
class BookRepositoryTest {
@Autowired BookRepository books;
@Test
void findsByAuthor() {
books.save(new Book("Dune", "Herbert", 15.0));
List<Book> found = books.findByAuthor("Herbert");
assertThat(found).hasSize(1);
assertThat(found.get(0).getTitle()).isEqualTo("Dune");
}
}When @SpringBootTest: an end-to-end test that loads the entire application context — every bean, real wiring. Note: with webEnvironment = RANDOM_PORT it starts a real server you call with TestRestTemplate. Slower than slices, so keep these few and use slices for the rest.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class BookstoreApplicationTests {
@Autowired TestRestTemplate rest;
@Test
void listEndpointWorks() {
ResponseEntity<Book[]> response =
rest.getForEntity("/api/books", Book[].class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}