Testing
Writing tests might feel like extra work at first, but trust me โ it's the best investment you can make. Tests are like a safety net that catches bugs before your users do. When you refactor code at 2 AM, tests make sure you didn't break anything.
Spring Boot gives you excellent testing support out of the box. You can test everything from individual components to the entire application context. No excuses.
@SpringBootTest
@SpringBootTest loads the entire application context for testing. It's like firing up the whole app but in a test environment. Use this when you need to test things that involve multiple components working together.
The downside? It's slower because it loads everything. For quick unit tests, consider smaller test slices like @WebMvcTest or @DataJpaTest instead.
@SpringBootTest
class UserServiceTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
void shouldCreateUser() {
User user = new User("John", "john@example.com");
User saved = userService.createUser(user);
assertThat(saved.getId()).isNotNull();
assertThat(saved.getName()).isEqualTo("John");
}
@Test
void shouldThrowOnDuplicateEmail() {
User user1 = new User("John", "john@example.com");
User user2 = new User("Jane", "john@example.com");
userService.createUser(user1);
assertThrows(DuplicateEmailException.class,
() -> userService.createUser(user2));
}
}
@WebMvcTest and @DataJpaTest
@WebMvcTest only loads the web layer โ controllers, filters, and related components. It's perfect for testing your REST endpoints without spinning up the entire app. Much faster than @SpringBootTest.
@DataJpaTest only loads the persistence layer โ your repositories, entities, and database configuration. It even rolls back changes after each test automatically. No cleanup needed.
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void shouldReturnUser() throws Exception {
User user = new User("John", "john@example.com");
when(userService.findById(1L)).thenReturn(user);
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"));
}
}
MockMvc for API Testing
MockMvc is your tool for testing REST APIs without actually starting a server. You can simulate HTTP requests and verify the responses. It's like a dry run for your endpoints.
You can test status codes, response bodies, headers, and even error scenarios. MockMvc makes it easy to write comprehensive API tests that give you real confidence in your code.
@Test
void shouldReturn404WhenUserNotFound() throws Exception {
when(userService.findById(99L))
.thenThrow(new ResourceNotFoundException("User", "id", 99L));
mockMvc.perform(get("/api/users/99"))
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.message").value("User not found with id: '99'"));
}
@Test
void shouldValidateUserInput() throws Exception {
User badUser = new User("", "invalid-email");
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(badUser)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.message").exists());
}