← Back to Module 3

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.

Incremental Integration

Components are integrated and tested one at a time.

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));
}

Video Content