Integration Testing
What is Integration Testing?
Integration testing is a level of software testing where individual components are combined and tested as a group. The purpose is to expose faults in the interaction between integrated components. This type of testing focuses on verifying that different parts of the application work together correctly.
Types of Integration Testing
Big Bang Integration
All components are integrated at once and tested as a whole.
- Pros: Simple to implement
- Cons: Difficult to identify issues
Incremental Integration
Components are integrated and tested one at a time.
- Top-down: Testing from top to bottom
- Bottom-up: Testing from bottom to top
- Sandwich: Combination of top-down and bottom-up
Spring Boot Integration Testing
Test Configuration
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@Test
void createUser_ValidData_ReturnsCreatedUser() throws Exception {
// Given
UserDTO userDTO = new UserDTO("john@example.com", "password123");
// When/Then
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(userDTO)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.email").value("john@example.com"));
}
}
Database Integration Testing
@DataJpaTest
public class UserRepositoryIntegrationTest {
@Autowired
private UserRepository userRepository;
@Test
void findByEmail_ExistingUser_ReturnsUser() {
// Given
User user = new User("john@example.com", "password123");
userRepository.save(user);
// When
Optional found = userRepository.findByEmail("john@example.com");
// Then
assertTrue(found.isPresent());
assertEquals("john@example.com", found.get().getEmail());
}
}
API Integration Testing
REST Assured Example
import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class UserApiIntegrationTest {
@BeforeEach
void setup() {
RestAssured.baseURI = "http://localhost:8080";
}
@Test
void getUser_ExistingUser_ReturnsUser() {
given()
.when()
.get("/api/users/1")
.then()
.statusCode(200)
.body("email", equalTo("john@example.com"))
.body("name", equalTo("John Doe"));
}
}
Testing Error Scenarios
@Test
void createUser_InvalidData_ReturnsBadRequest() throws Exception {
// Given
UserDTO invalidUser = new UserDTO("invalid-email", "");
// When/Then
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(invalidUser)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errors").isArray())
.andExpect(jsonPath("$.errors[0].field").value("email"));
}
Test Data Management
Test Containers
@SpringBootTest
@Testcontainers
public class DatabaseIntegrationTest {
@Container
static PostgreSQLContainer> postgres = new PostgreSQLContainer<>("postgres:13");
@DynamicPropertySource
static void postgresProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Test
void testDatabaseConnection() {
assertTrue(postgres.isRunning());
}
}
Test Data Setup
@BeforeEach
void setupTestData() {
// Clear existing data
userRepository.deleteAll();
// Create test data
User user1 = new User("user1@example.com", "password123");
User user2 = new User("user2@example.com", "password456");
userRepository.saveAll(Arrays.asList(user1, user2));
}