@EmbeddedKafka has long been the standard for Kafka testing in Spring Boot. It works, but it runs a different Kafka implementation than production — one that can accept messages and serialize records in ways that a real Kafka broker would not. KafkaContainer runs the same Confluent Kafka image your production environment uses, with the same broker configuration, same partition behavior, and same consumer group offset management. This article shows how to test Kafka producers, consumers, and dead-letter topics with a real broker.
Continue reading »Integration-Testing
9 posts in this section
MySQL Testing with Testcontainers
MySQL is still the most widely deployed relational database in Java applications. Its SQL dialect, strict mode behavior, and character set handling differ from both H2 and PostgreSQL in ways that matter for real applications. This article covers MySQL testing with Testcontainers — from basic setup to MySQL-specific features and the STRICT_TRANS_TABLES mode that catches data truncation bugs H2 silently ignores. What You’ll Learn MySQLContainer setup and configuration @ServiceConnection with MySQL MySQL strict mode and why it matters for tests Character set and collation configuration Testing MySQL-specific SQL functions MariaDB as an alternative Dependencies <dependency> <groupId>org.
Continue reading »PostgreSQL Testing with Testcontainers
Testing database code against H2 gives you a false sense of security. PostgreSQL has different behavior for ON CONFLICT, RETURNING, JSON operators, full-text search, and dozens of other features. A JPA query that works in H2 dialect may fail against real PostgreSQL. This article shows how to test your Spring Data JPA repositories, custom queries, and database constraints against a real PostgreSQL instance using Testcontainers. What You’ll Learn @ServiceConnection — the Spring Boot 3.
Continue reading »RabbitMQ Testing with Testcontainers
RabbitMQ’s exchange-queue model, routing keys, dead-letter exchanges, and message TTL are features that cannot be tested with mocks. The broker’s routing logic — topic exchange patterns, fanout behavior, message acknowledgment, and requeue behavior on rejection — all require a real broker. This article covers RabbitMQ integration testing with RabbitMQContainer. What You’ll Learn RabbitMQContainer setup and @ServiceConnection Configuring exchanges, queues, and bindings for tests Testing @RabbitListener consumers with Awaitility Testing dead-letter exchange and dead-letter queue routing Testing message TTL and automatic expiry Testing acknowledgment modes Dependencies <dependency> <groupId>org.
Continue reading »Redis Testing with Testcontainers
Redis cache testing with a real Redis instance catches behaviors that embedded or mocked alternatives cannot: TTL expiry timing, cache eviction under memory pressure, cluster failover behavior, and the exact serialization format that Redis stores data in. This article covers testing Spring Cache, Spring Session, and distributed locks against a real Redis container. What You’ll Learn Redis GenericContainer setup and @ServiceConnection (Spring Boot 3.2+) Testing Spring Cache with @Cacheable, @CacheEvict, and @CachePut Verifying TTL expiry behavior Testing Spring Session with Redis Testing distributed locks with Redisson or Spring Integration Dependencies <dependency> <groupId>org.
Continue reading »Unit Testing vs Integration Testing vs System Testing in Java
“We have 90% test coverage” means nothing if 90% of your tests are mocking away the parts that matter. A codebase full of unit tests that mock every dependency can have excellent coverage numbers while completely missing bugs that manifest when real components interact. Understanding the difference between unit tests, integration tests, and system tests — and when to use each — is the foundation of a test suite that actually finds bugs.
Continue reading »WireMock — Testing External REST API Integrations
Most Spring Boot applications call external APIs — payment gateways, shipping providers, notification services, CRM systems. Testing these integrations is hard because external APIs have rate limits, authentication requirements, and a habit of being unavailable at exactly the wrong moment. WireMock runs a real HTTP server in a Docker container, accepts your requests, and returns whatever responses you configure. This article covers WireMock as a Testcontainer for testing Spring Boot REST client integrations.
Continue reading »Integration Testing with @SpringBootTest and Testcontainers
Integration tests verify that all layers work together — HTTP → controller → service → repository → database. This article shows how to write them efficiently with Testcontainers and manage test isolation. @SpringBootTest — The Full Context @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class OrderIntegrationTest { // Loads the FULL Spring ApplicationContext // Everything: controllers, services, repositories, security // Starts on a random port (avoids port conflicts when running tests in parallel) } WebEnvironment options Option What it starts Use for RANDOM_PORT Embedded server on random port Full HTTP round-trip tests DEFINED_PORT Embedded server on configured port When you need a fixed port MOCK (default) No real server, MockMvc available Fast tests without real HTTP NONE No server at all Service/repo tests only Testcontainers — Real Database <dependency> <groupId>org.
Continue reading »Spring Boot Testing with Testcontainers: The Right Way
Testcontainers spins up real Docker containers for your tests — a real PostgreSQL database, a real Redis, a real Kafka broker. No more mocking JDBC connections or in-memory H2 databases that behave differently from production. Spring Boot 3.1 added @ServiceConnection, which removes the boilerplate of configuring connection URLs manually. This guide covers the right patterns for fast, reliable integration tests with Testcontainers. Why Testcontainers Over H2 Teams use H2 in-memory databases for testing because it’s fast.
Continue reading »