Advanced Testing in Spring Boot

1️⃣ Introduction

Advanced testing in Spring Boot involves using sophisticated tools and techniques to ensure application reliability and performance. This article explores various testing approaches and their implementation.

Key features include:

  • Testcontainers for containerized testing
  • Contract testing for service interactions
  • MockWebServer for HTTP testing
  • Performance testing with JMeter
  • Integration testing strategies

2️⃣ Key Concepts & Terminology

  • Testcontainers: Library for running Docker containers in tests
  • Contract Testing: Testing service interactions and contracts
  • MockWebServer: Mock HTTP server for testing HTTP clients
  • Performance Testing: Testing application performance under load
  • Integration Testing: Testing component interactions

3️⃣ Hands-on Implementation 🛠

🔹 Step 1: Testcontainers Setup

@SpringBootTest
@AutoConfigureMockMvc
@Testcontainers
public class UserServiceIntegrationTest {
    @Container
    static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:13");

    @Autowired
    private UserService userService;

    @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 shouldCreateUser() {
        User user = new User("test@example.com", "password");
        User saved = userService.createUser(user);
        assertThat(saved.getId()).isNotNull();
    }
}

🔹 Step 2: Contract Testing

@SpringBootTest
@AutoConfigureStubRunner
public class ContractTest {
    @StubRunnerPort("user-service")
    int userServicePort;

    @Test
    void shouldGetUser() {
        RestTemplate restTemplate = new RestTemplate();
        User user = restTemplate.getForObject(
            "http://localhost:" + userServicePort + "/api/users/1",
            User.class
        );
        assertThat(user).isNotNull();
    }
}

// Contract definition
Contract.make {
    request {
        method 'GET'
        url '/api/users/1'
    }
    response {
        status 200
        body([
            id: 1,
            email: 'test@example.com',
            name: 'Test User'
        ])
    }
}

🔹 Step 3: MockWebServer Usage

@SpringBootTest
public class ExternalServiceTest {
    private MockWebServer mockWebServer;

    @BeforeEach
    void setup() throws IOException {
        mockWebServer = new MockWebServer();
        mockWebServer.start();
    }

    @AfterEach
    void tearDown() throws IOException {
        mockWebServer.shutdown();
    }

    @Test
    void shouldCallExternalService() {
        mockWebServer.enqueue(new MockResponse()
            .setBody("{\"id\": 1, \"name\": \"Test\"}")
            .addHeader("Content-Type", "application/json"));

        ExternalService service = new ExternalService(mockWebServer.url("/").toString());
        Response response = service.getData();
        assertThat(response.getId()).isEqualTo(1);
    }
}

4️⃣ Common Issues & Debugging 🐞

Common Issues and Solutions

Issue Solution
Container startup issues Check Docker daemon and container logs
Contract test failures Verify contract definitions and service responses
Mock server errors Check request/response matching

5️⃣ Q&A / Frequently Asked Questions

Use Testcontainers when you need to test against the actual database (e.g., PostgreSQL) to catch vendor-specific issues. Use H2 for faster tests that don't require specific database features.

Use container reuse, parallel execution, and proper cleanup. Consider using @Container(parallel = true) and implementing proper shutdown hooks.

6️⃣ Best Practices & Pro Tips 🚀

  • Use appropriate test containers
  • Implement proper cleanup
  • Write meaningful contracts
  • Mock external services
  • Monitor test performance
  • Use test profiles

7️⃣ Read Next 📖

8️⃣ Conclusion

Advanced testing in Spring Boot requires understanding various tools and techniques. Proper implementation of Testcontainers, Contract Testing, and MockWebServer is crucial for reliable tests.

Remember to follow best practices, handle test data properly, and maintain test performance for efficient development.