The CI pipeline from Article 19 validates migrations against a MySQL service container. But that’s not the same as testing that your application code works correctly after the migration runs. This article covers how to structure Spring Boot tests that validate both the migration and the application behaviour — and makes the case for replacing H2 with Testcontainers as your primary testing database. Three Testing Strategies Strategy Database Speed Fidelity Use For H2 in-memory H2 (in-memory) Fastest Low — MySQL-specific SQL fails Unit tests that mock repositories H2 with MySQL mode H2 (MySQL compat) Fast Medium — most SQL works, some quirks Basic integration tests on simple schemas Testcontainers Real MySQL 8.
Continue reading »Tutorial
264 posts in this section
Testing Secured Endpoints
Security tests verify that your endpoints behave correctly for different users, roles, and authentication states. This article covers the full toolkit — from simple annotations to custom security contexts. Setup <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> spring-boot-starter-test includes this automatically. @WithMockUser — Simple Role-Based Tests The simplest way to run a test as an authenticated user: @WebMvcTest(OrderController.class) class OrderControllerSecurityTest { @Autowired MockMvc mockMvc; @MockBean OrderService orderService; // No authentication @Test void unauthenticatedUserIsRejected() throws Exception { mockMvc.
Continue reading »Testing Spring Batch Jobs: Unit Tests, Integration Tests, and @SpringBatchTest
Introduction Spring Batch jobs are code — they need tests. Without tests you will catch errors in production. With tests you catch them in CI. Spring Batch has a dedicated testing module that provides @SpringBatchTest, JobLauncherTestUtils, and JobRepositoryTestUtils. These tools let you: Run a complete job in a test and assert on its BatchStatus Launch individual steps and inspect StepExecution counters Test readers, processors, and writers in complete isolation This article covers all three levels: unit, integration, and database integration with Testcontainers.
Continue reading »Testing Spring Boot Apps: Unit Tests with JUnit 5 and Mockito
Good tests catch regressions, document behavior, and give you confidence to refactor. Bad tests slow you down. This article covers unit testing at the service layer — fast, focused, no Spring context needed. Setup <!-- spring-boot-starter-test includes JUnit 5, Mockito, AssertJ --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> This pulls in: JUnit 5 (Jupiter) — test runner and assertions Mockito — mocking framework AssertJ — fluent assertions (assertThat(...)) Hamcrest — matcher library MockMvc — web layer testing (next article) Testcontainers integration Unit Tests vs Integration Tests Unit Integration Scope One class in isolation Multiple components together Dependencies All mocked Real or near-real Speed Milliseconds Seconds to minutes Context No Spring context Spring context loads Purpose Logic correctness Component interaction Start with unit tests.
Continue reading »Testing the Repository Layer with @DataJpaTest
Repository tests verify your queries work correctly against a real database. Spring Boot’s @DataJpaTest starts a minimal slice — only JPA components — making tests fast while still catching real SQL issues. @DataJpaTest — What It Loads @DataJpaTest is a test slice annotation: @DataJpaTest class OrderRepositoryTest { // Spring loads: // - Your @Entity classes // - Your @Repository interfaces // - JPA infrastructure (EntityManager, transactions) // - An in-memory H2 database (by default) // // Spring does NOT load: // - @Service, @Controller, @Component classes // - Security configuration // - The full ApplicationContext } Each test method runs in a transaction that’s rolled back at the end — no data pollution between tests.
Continue reading »Testing the Web Layer with @WebMvcTest and MockMvc
Controller tests verify HTTP mapping, request parsing, validation, serialization, and security — without starting a full server. @WebMvcTest + MockMvc gives you a fast, focused web layer test. @WebMvcTest — What It Loads @WebMvcTest(OrderController.class) class OrderControllerTest { // Spring loads: // - Your @Controller class (and its dependencies) // - DispatcherServlet, MVC configuration // - Jackson ObjectMapper // - Security (if configured) // // Spring does NOT load: // - @Service, @Repository beans // - Database, JPA // // You @MockBean all services } Basic Controller Test @WebMvcTest(OrderController.
Continue reading »Transactions: @Transactional, Propagation, and Isolation Levels
A transaction ensures that a group of operations either all succeed or all fail — no partial state. Spring’s @Transactional makes this simple to use, but the underlying mechanics matter when things go wrong. How @Transactional Works @Transactional is implemented via AOP (Aspect-Oriented Programming). Spring wraps your bean in a proxy: Client calls orderService.create() │ ▼ Spring AOP proxy intercepts the call │ ▼ BEGIN TRANSACTION │ ▼ Your actual method body executes (all DB operations share one connection and transaction) │ ├─ No exception → COMMIT │ └─ RuntimeException thrown → ROLLBACK │ ▼ Client receives result (or exception) This means @Transactional only works when:
Continue reading »Transforming Data with ItemProcessor: Validation, Filtering, and Enrichment
Introduction ItemProcessor<I, O> sits between the reader and the writer. It receives one item at a time and returns a transformed item — or null to filter the item out entirely. Processors are optional: if your job reads and writes the same type with no transformation needed, you can omit them. The processor interface is one method: public interface ItemProcessor<I, O> { O process(I item) throws Exception; } Return a processed item to pass it to the writer.
Continue reading »Troubleshooting: 10 Common Liquibase Errors and How to Fix Them
Liquibase errors tend to cluster around the same ten problems. You will hit most of them at least once. This article gives you the exact error message to search for, the root cause, and the fastest fix — so you spend minutes recovering, not hours debugging. Error 1: DATABASECHANGELOGLOCK — “Waiting for changelog lock” Symptoms Waiting for changelog lock.... Waiting for changelog lock.... Waiting for changelog lock.... liquibase.exception.LockException: Could not acquire change log lock.
Continue reading »What's New in Spring Boot 4.0
Spring Boot 4.0 (November 2025) is a major release built on Spring Framework 7 and Java 17+. It’s the most significant Spring release since Boot 3’s Jakarta EE migration. This article covers every change that affects a practicing developer. Minimum Requirements Spring Boot 3.x Spring Boot 4.0 Java 17 17 (baseline), 21 recommended Spring Framework 6.x 7.x Jakarta EE 10 11 Tomcat 10.x 11.x Hibernate 6.x 7.x Gradle (if used) 7.
Continue reading »