Spring-Boot

209 posts in this section

JUnit 5 Integration — Lifecycle and Annotations

The biggest performance factor in a Testcontainers test suite is how many times you start and stop containers. Start a PostgreSQL container once per JVM and your tests add 2 seconds to total CI time. Start it once per test method and 50 tests cost 100 seconds. Understanding Testcontainers lifecycle management is how you write fast tests without sacrificing isolation. This article covers all the container lifecycle options in JUnit 5 — from the simplest @Container annotation to the singleton pattern that shares one container across your entire test suite.

Continue reading »

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 »

Setting Up Testcontainers in a Java Project

Setting up Testcontainers takes about five minutes. The dependencies are on Maven Central, the BOM manages all version alignment, and Spring Boot 3 has first-class support that eliminates most of the configuration boilerplate. By the end of this article, you will have a Spring Boot project with Testcontainers running, a PostgreSQL container backing your first integration test, and a clear understanding of how to add any additional container module. What You’ll Learn How the Testcontainers BOM works and why you need it Which dependencies to add for Spring Boot, PostgreSQL, and JUnit 5 How to configure Maven and Gradle for Testcontainers tests How to set up Logback so you can see container startup logs How @ServiceConnection eliminates @DynamicPropertySource boilerplate in Spring Boot 3.

Continue reading »

Singleton Containers and Shared Base Classes

With 20 integration test classes, each starting its own PostgreSQL container, you pay 20 container starts at 2 seconds each — 40 seconds of pure overhead before a single assertion runs. The singleton pattern starts one container per JVM, shares it across all test classes, and cuts that 40 seconds to 2. This is the most impactful performance optimization for large Testcontainers test suites. What You’ll Learn The singleton pattern using a static initializer block Abstract base class design for sharing containers and @DynamicPropertySource Why you must not combine @Testcontainers/@Container with the singleton pattern Spring TestContext caching — how it works and how to maximize reuse The @ImportTestcontainers approach for Spring Boot 3.

Continue reading »

Spring Boot Testing Slices — @DataJpaTest, @WebMvcTest, and @SpringBootTest

@SpringBootTest starts the full application context — all beans, all auto-configurations, all datasources, all message listeners. That is 10–30 seconds of startup time for every test class that needs it. Spring Boot’s test slices load a subset of the application context — only the beans relevant to what you are testing. Repository tests that once took 15 seconds with @SpringBootTest take 2 seconds with @DataJpaTest. This article covers all the major test slices and how to combine them with Testcontainers.

Continue reading »

Testcontainers in CI/CD — GitHub Actions, Docker, and Production Patterns

Testcontainers tests that run perfectly on your developer laptop can fail in CI for environmental reasons — Docker daemon availability, image pull timeouts, port conflicts, and resource limits. This final article covers production-ready CI/CD configuration for Testcontainers in GitHub Actions, GitLab CI, and Jenkins, plus Spring Boot 3.1’s development-time container support. What You’ll Learn GitHub Actions configuration for Testcontainers (zero extra setup on ubuntu-latest) GitLab CI configuration with Docker-in-Docker Jenkins configuration with Docker socket mounting TestApplication — running your app locally with containers instead of a real database .

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 »

What Is Testcontainers and Why You Need It

Your CI pipeline goes green. You deploy to staging. The application crashes on startup because Flyway migrations fail against MySQL — but all your tests used H2. Your team has seen this before. Tests that pass on every machine, fail in production. Not because the business logic was wrong, but because the test infrastructure was fake. This is the problem Testcontainers was built to solve. This article covers what Testcontainers is, why traditional approaches to integration testing fall short, and how Testcontainers gives you test environments that match production — automatically, repeatably, with no shared test database to maintain.

Continue reading »

@MappedSuperclass: Sharing Fields Without Inheritance Tables

Introduction Almost every entity in a real application shares a few common fields: id, createdAt, updatedAt, and perhaps version. Writing these in every entity class is repetitive and error-prone. @MappedSuperclass lets you define them once in a base class that all entities extend — without creating a parent table or any inheritance mapping in the database. What Is @MappedSuperclass? @MappedSuperclass marks a class whose field mappings are inherited by subclass entities.

Continue reading »