Spring Boot Topic
Spring Boot Testing
1. Introduction to Spring Boot Testing
Spring Boot Testing provides a comprehensive set of tools and annotations for testing Spring Boot applications. It builds on the Spring TestContext Framework and provides auto-configuration for various testing scenarios.
Key Features:
-
Auto-configuration: Automatic setup of application context
-
Test Slices: Test specific layers of your application
-
Mocking Support: Built-in support for mocking beans
-
Test Containers: Integration with Testcontainers for database testing
-
Web Testing: Support for testing MVC controllers and WebFlux
Testing Pyramid:
-
Unit Tests (70%): Test individual components in isolation
-
Integration Tests (20%): Test interactions between components
-
End-to-End Tests (10%): Test complete application flow
2. Test Dependencies
Maven Dependencies
<dependencies>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Test Containers -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<!-- Additional Testing Libraries -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
What's Included in spring-boot-starter-test:
-
JUnit 5: The default testing framework
-
Spring Test & Spring Boot Test: Utilities and integration test support
-
AssertJ: Fluent assertions library
-
Hamcrest: Matcher library
-
Mockito: Mocking framework
-
JSONassert: JSON assertion library
-
JsonPath: XPath for JSON
3. Unit Testing
3.1 Testing Service Layer with Mocking
Service Class:
@Service
@Transactional
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
public UserService(UserRepository userRepository, EmailService emailService) {
this.userRepository = userRepository;
this.emailService = emailService;
}
public User createUser(User user) {
if (userRepository.existsByEmail(user.getEmail())) {
throw new UserAlreadyExistsException("Email already exists: " + user.getEmail());
}
User savedUser = userRepository.save(user);
emailService.sendWelcomeEmail(user.getEmail());
return savedUser;
}
public Optional<User> getUserById(Long id) {
return userRepository.findById(id);
}
public List<User> searchUsers(String keyword) {
return userRepository.findByUsernameContainingOrEmailContaining(keyword, keyword);
}
}
Unit Test:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class UserServiceUnitTest {
@Mock
private UserRepository userRepository;
@Mock
private EmailService emailService;
@InjectMocks
private UserService userService;
@Test
void whenCreateUserWithValidData_thenUserIsCreated() {
// Given
User user = new User("john.doe", "john@example.com");
User savedUser = new User(1L, "john.doe", "john@example.com");
when(userRepository.existsByEmail("john@example.com")).thenReturn(false);
when(userRepository.save(any(User.class))).thenReturn(savedUser);
doNothing().when(emailService).sendWelcomeEmail(anyString());
// When
User result = userService.createUser(user);
// Then
assertThat(result).isNotNull();
assertThat(result.getId()).isEqualTo(1L);
assertThat(result.getUsername()).isEqualTo("john.doe");
verify(userRepository).existsByEmail("john@example.com");
verify(userRepository).save(user);
verify(emailService).sendWelcomeEmail("john@example.com");
}
@Test
void whenCreateUserWithExistingEmail_thenThrowException() {
// Given
User user = new User("john.doe", "existing@example.com");
when(userRepository.existsByEmail("existing@example.com")).thenReturn(true);
// When & Then
assertThatThrownBy(() -> userService.createUser(user))
.isInstanceOf(UserAlreadyExistsException.class)
.hasMessage("Email already exists: existing@example.com");
verify(userRepository, never()).save(any(User.class));
verify(emailService, never()).sendWelcomeEmail(anyString());
}
@Test
void whenGetUserById_thenReturnUser() {
// Given
User user = new User(1L, "john.doe", "john@example.com");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
// When
Optional<User> result = userService.getUserById(1L);
// Then
assertThat(result).isPresent();
assertThat(result.get().getUsername()).isEqualTo("john.doe");
}
@Test
void whenGetNonExistentUser_thenReturnEmpty() {
// Given
when(userRepository.findById(999L)).thenReturn(Optional.empty());
// When
Optional<User> result = userService.getUserById(999L);
// Then
assertThat(result).isEmpty();
}
}
3.2 Testing Utility Classes
Utility Class:
@Component
public class PasswordValidator {
private static final String PASSWORD_PATTERN =
"^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$";
public boolean isValid(String password) {
if (password == null) {
return false;
}
return password.matches(PASSWORD_PATTERN);
}
public List<String> validatePassword(String password) {
List<String> errors = new ArrayList<>();
if (password == null || password.length() < 8) {
errors.add("Password must be at least 8 characters long");
}
if (password != null && !password.matches(".*[0-9].*")) {
errors.add("Password must contain at least one digit");
}
if (password != null && !password.matches(".*[a-z].*")) {
errors.add("Password must contain at least one lowercase letter");
}
if (password != null && !password.matches(".*[A-Z].*")) {
errors.add("Password must contain at least one uppercase letter");
}
return errors;
}
}
Unit Test:
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
class PasswordValidatorTest {
private PasswordValidator passwordValidator;
@BeforeEach
void setUp() {
passwordValidator = new PasswordValidator();
}
@ParameterizedTest
@ValueSource(strings = {
"ValidPass1!",
"StrongP@ss123",
"Test123#Password"
})
@DisplayName("Should return true for valid passwords")
void whenPasswordIsValid_thenReturnTrue(String password) {
// When & Then
assertThat(passwordValidator.isValid(password)).isTrue();
}
@ParameterizedTest
@ValueSource(strings = {
"weak",
"nouppercase1!",
"NOLOWERCASE1!",
"NoSpecialChar123",
"Short1!"
})
@DisplayName("Should return false for invalid passwords")
void whenPasswordIsInvalid_thenReturnFalse(String password) {
// When & Then
assertThat(passwordValidator.isValid(password)).isFalse();
}
@Test
@DisplayName("Should return specific validation errors")
void whenPasswordValidationFails_thenReturnSpecificErrors() {
// Given
String weakPassword = "weak";
// When
List<String> errors = passwordValidator.validatePassword(weakPassword);
// Then
assertThat(errors)
.hasSize(4)
.contains(
"Password must be at least 8 characters long",
"Password must contain at least one digit",
"Password must contain at least one uppercase letter",
"Password must contain at least one lowercase letter"
);
}
@Test
@DisplayName("Should return empty list for valid password")
void whenPasswordIsValid_thenReturnEmptyErrorList() {
// Given
String validPassword = "ValidPass1!";
// When
List<String> errors = passwordValidator.validatePassword(validPassword);
// Then
assertThat(errors).isEmpty();
}
}
4. Integration Testing
4.1 Data JPA Tests
Repository Test:
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestPropertySource;
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestPropertySource(properties = {
"spring.jpa.hibernate.ddl-auto=create-drop",
"spring.jpa.show-sql=true"
})
class UserRepositoryIntegrationTest {
@Autowired
private TestEntityManager testEntityManager;
@Autowired
private UserRepository userRepository;
@Test
void whenFindByEmail_thenReturnUser() {
// Given
User user = new User("jane.doe", "jane@example.com");
testEntityManager.persistAndFlush(user);
// When
Optional<User> found = userRepository.findByEmail("jane@example.com");
// Then
assertThat(found).isPresent();
assertThat(found.get().getUsername()).isEqualTo("jane.doe");
}
@Test
void whenFindByNonExistentEmail_thenReturnEmpty() {
// When
Optional<User> found = userRepository.findByEmail("nonexistent@example.com");
// Then
assertThat(found).isEmpty();
}
@Test
void whenExistsByEmail_thenReturnTrue() {
// Given
User user = new User("john.doe", "john@example.com");
testEntityManager.persistAndFlush(user);
// When
boolean exists = userRepository.existsByEmail("john@example.com");
// Then
assertThat(exists).isTrue();
}
@Test
void whenFindByUsernameContaining_thenReturnUsers() {
// Given
User user1 = new User("john.doe", "john@example.com");
User user2 = new User("jane.doe", "jane@example.com");
User user3 = new User("bob.smith", "bob@example.com");
testEntityManager.persist(user1);
testEntityManager.persist(user2);
testEntityManager.persist(user3);
testEntityManager.flush();
// When
List<User> users = userRepository.findByUsernameContaining("doe");
// Then
assertThat(users)
.hasSize(2)
.extracting(User::getUsername)
.containsExactlyInAnyOrder("john.doe", "jane.doe");
}
}
4.2 Service Layer Integration Test
Service Integration Test:
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
@SpringBootTest
@ActiveProfiles("test")
@Transactional
class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
void whenCreateUser_thenUserIsPersisted() {
// Given
User user = new User("test.user", "test@example.com");
// When
User savedUser = userService.createUser(user);
// Then
assertThat(savedUser.getId()).isNotNull();
Optional<User> foundUser = userRepository.findById(savedUser.getId());
assertThat(foundUser).isPresent();
assertThat(foundUser.get().getUsername()).isEqualTo("test.user");
}
@Test
void whenCreateUserWithDuplicateEmail_thenThrowException() {
// Given
User user1 = new User("user1", "duplicate@example.com");
userService.createUser(user1);
User user2 = new User("user2", "duplicate@example.com");
// When & Then
assertThatThrownBy(() -> userService.createUser(user2))
.isInstanceOf(UserAlreadyExistsException.class);
}
}
5. Web Layer Testing
5.1 Testing REST Controllers with @WebMvcTest
Controller:
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.getAllUsers();
return ResponseEntity.ok(users);
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.getUserById(id)
.orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));
return ResponseEntity.ok(user);
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody @Valid CreateUserRequest request) {
User user = new User(request.getUsername(), request.getEmail());
User createdUser = userService.createUser(user);
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id,
@RequestBody @Valid UpdateUserRequest request) {
User user = userService.getUserById(id)
.orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));
user.setUsername(request.getUsername());
user.setEmail(request.getEmail());
User updatedUser = userService.updateUser(user);
return ResponseEntity.ok(updatedUser);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
Controller Test:
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import com.fasterxml.jackson.databind.ObjectMapper;
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private UserService userService;
@Test
void whenGetAllUsers_thenReturnUsers() throws Exception {
// Given
List<User> users = Arrays.asList(
new User(1L, "john.doe", "john@example.com"),
new User(2L, "jane.doe", "jane@example.com")
);
when(userService.getAllUsers()).thenReturn(users);
// When & Then
mockMvc.perform(get("/api/users")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$[0].username").value("john.doe"))
.andExpect(jsonPath("$[1].username").value("jane.doe"));
}
@Test
void whenGetExistingUser_thenReturnUser() throws Exception {
// Given
User user = new User(1L, "john.doe", "john@example.com");
when(userService.getUserById(1L)).thenReturn(Optional.of(user));
// When & Then
mockMvc.perform(get("/api/users/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.username").value("john.doe"))
.andExpect(jsonPath("$.email").value("john@example.com"));
}
@Test
void whenGetNonExistentUser_thenReturnNotFound() throws Exception {
// Given
when(userService.getUserById(999L)).thenReturn(Optional.empty());
// When & Then
mockMvc.perform(get("/api/users/999")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
}
@Test
void whenCreateValidUser_thenReturnCreated() throws Exception {
// Given
CreateUserRequest request = new CreateUserRequest("new.user", "new@example.com");
User createdUser = new User(1L, "new.user", "new@example.com");
when(userService.createUser(any(User.class))).thenReturn(createdUser);
// When & Then
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.username").value("new.user"))
.andExpect(jsonPath("$.email").value("new@example.com"));
}
@Test
void whenCreateUserWithInvalidData_thenReturnBadRequest() throws Exception {
// Given
CreateUserRequest request = new CreateUserRequest("", "invalid-email");
// When & Then
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errors").exists());
}
@Test
void whenUpdateUser_thenReturnUpdatedUser() throws Exception {
// Given
UpdateUserRequest request = new UpdateUserRequest("updated.user", "updated@example.com");
User existingUser = new User(1L, "old.user", "old@example.com");
User updatedUser = new User(1L, "updated.user", "updated@example.com");
when(userService.getUserById(1L)).thenReturn(Optional.of(existingUser));
when(userService.updateUser(any(User.class))).thenReturn(updatedUser);
// When & Then
mockMvc.perform(put("/api/users/1")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("updated.user"))
.andExpect(jsonPath("$.email").value("updated@example.com"));
}
@Test
void whenDeleteUser_thenReturnNoContent() throws Exception {
// Given
doNothing().when(userService).deleteUser(1L);
// When & Then
mockMvc.perform(delete("/api/users/1"))
.andExpect(status().isNoContent());
verify(userService).deleteUser(1L);
}
}
5.2 Testing with @SpringBootTest and TestRestTemplate
Integration Test with Real HTTP Calls:
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class UserControllerIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private UserRepository userRepository;
private String baseUrl;
@BeforeEach
void setUp() {
baseUrl = "http://localhost:" + port + "/api/users";
userRepository.deleteAll();
}
@Test
@Order(1)
void whenCreateUser_thenUserIsCreated() {
// Given
CreateUserRequest request = new CreateUserRequest("integration.user", "integration@example.com");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<CreateUserRequest> entity = new HttpEntity<>(request, headers);
// When
ResponseEntity<User> response = restTemplate.exchange(
baseUrl, HttpMethod.POST, entity, User.class);
// Then
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getId()).isNotNull();
assertThat(response.getBody().getUsername()).isEqualTo("integration.user");
// Verify in database
Optional<User> savedUser = userRepository.findByEmail("integration@example.com");
assertThat(savedUser).isPresent();
}
@Test
@Order(2)
void whenGetUser_thenReturnUser() {
// Given - Create user first
User user = new User("test.user", "test@example.com");
User savedUser = userRepository.save(user);
// When
ResponseEntity<User> response = restTemplate.getForEntity(
baseUrl + "/" + savedUser.getId(), User.class);
// Then
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getUsername()).isEqualTo("test.user");
}
}
6. Test Slices
Available Test Slices:
| Annotation | Purpose | Auto-configures |
|---|---|---|
@WebMvcTest |
MVC controller tests | MVC infrastructure, @Controller beans |
@DataJpaTest |
JPA repository tests | DataSource, EntityManager, @Repository beans |
@JsonTest |
JSON serialization tests | JSON mappers (Jackson, Gson) |
@DataMongoTest |
MongoDB tests | MongoTemplate, @Document classes |
@RestClientTest |
REST client tests | REST client infrastructure |
@WebFluxTest |
WebFlux controller tests | WebFlux infrastructure |
Example of Different Test Slices:
JSON Test:
@JsonTest
class UserJsonTest {
@Autowired
private JacksonTester<User> json;
@Test
void whenSerializeUser_thenCorrectJson() throws Exception {
User user = new User(1L, "john.doe", "john@example.com");
assertThat(json.write(user))
.hasJsonPathNumberValue("$.id")
.hasJsonPathStringValue("$.username")
.hasJsonPathStringValue("$.email")
.extractingJsonPathStringValue("$.username").isEqualTo("john.doe");
}
@Test
void whenDeserializeJson_thenCorrectUser() throws Exception {
String userJson = """
{
"id": 1,
"username": "john.doe",
"email": "john@example.com"
}
""";
assertThat(json.parse(userJson))
.isEqualTo(new User(1L, "john.doe", "john@example.com"));
}
}
7. Test Configuration and Profiles
Test Configuration Class:
@TestConfiguration
public class TestConfig {
@Bean
@Primary
public UserService testUserService() {
return new UserService(testUserRepository(), testEmailService());
}
@Bean
@Primary
public UserRepository testUserRepository() {
return new InMemoryUserRepository();
}
@Bean
@Primary
public EmailService testEmailService() {
return mock(EmailService.class);
}
}
// In-memory repository for testing
public class InMemoryUserRepository implements UserRepository {
private final Map<Long, User> users = new HashMap<>();
private Long currentId = 1L;
@Override
public User save(User user) {
if (user.getId() == null) {
user.setId(currentId++);
}
users.put(user.getId(), user);
return user;
}
@Override
public Optional<User> findById(Long id) {
return Optional.ofNullable(users.get(id));
}
// Implement other methods...
}
Profile-specific Test Configuration:
@SpringBootTest
@ActiveProfiles("test")
@TestPropertySource(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.jpa.hibernate.ddl-auto=create-drop",
"logging.level.org.springframework.security=DEBUG"
})
class ProfileSpecificTest {
@Test
void whenTestProfileActive_thenUseTestConfiguration() {
// Test implementation
}
}
8. Advanced Testing Scenarios
8.1 Testing with Testcontainers
Database Integration Test:
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@Testcontainers
@SpringBootTest
@ActiveProfiles("test")
class UserRepositoryTestcontainersTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Autowired
private UserRepository userRepository;
@Test
void whenSaveUserInContainer_thenUserIsPersisted() {
// Given
User user = new User("container.user", "container@example.com");
// When
User savedUser = userRepository.save(user);
// Then
assertThat(savedUser.getId()).isNotNull();
assertThat(userRepository.count()).isEqualTo(1);
}
}
8.2 Testing Security
Security Test:
@WebMvcTest(UserController.class)
@WithMockUser
class UserControllerSecurityTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
@WithMockUser(roles = "USER")
void whenUserWithUserRoleAccessEndpoint_thenSuccess() throws Exception {
when(userService.getAllUsers()).thenReturn(Collections.emptyList());
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk());
}
@Test
@WithMockUser(roles = "ADMIN")
void whenUserWithAdminRoleAccessEndpoint_thenSuccess() throws Exception {
// Test admin access
}
@Test
@WithAnonymousUser
void whenAnonymousUserAccessSecuredEndpoint_thenUnauthorized() throws Exception {
mockMvc.perform(get("/api/users"))
.andExpect(status().isUnauthorized());
}
}
9. Best Practices
1. Test Structure (Given-When-Then)
@Test
void whenCondition_thenExpectedResult() {
// Given - setup test data and preconditions
User user = new User("test.user", "test@example.com");
// When - execute the action being tested
User result = userService.createUser(user);
// Then - verify the results
assertThat(result).isNotNull();
assertThat(result.getId()).isNotNull();
}
2. Meaningful Test Names
@Test
void whenCreateUserWithDuplicateEmail_thenThrowUserAlreadyExistsException() { }
@Test
void whenSearchUsersWithEmptyKeyword_thenReturnAllUsers() { }
@Test
void whenGetNonExistentUserById_thenReturnEmptyOptional() { }
3. Use AssertJ for Readable Assertions
assertThat(actualList)
.hasSize(3)
.containsExactlyInAnyOrder("item1", "item2", "item3")
.allMatch(item -> item.startsWith("item"));
4. Test Isolation
@BeforeEach
void setUp() {
// Reset state before each test
userRepository.deleteAll();
}
@AfterEach
void tearDown() {
// Clean up after each test
testEntityManager.clear();
}
5. Use Test Profiles
# application-test.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
logging.level.com.example=DEBUG
This comprehensive guide covers Spring Boot Testing from unit tests to integration tests, including advanced scenarios with Testcontainers and security testing. The key is to choose the right testing strategy based on what you're testing and use the appropriate test slices to keep tests focused and fast.
Comments (0)
No comments yet. Be the first to comment!