Test Flyway Java Migrations with Spring Boot

Last Updated:  June 16, 2025 | Published: June 16, 2025

Database migrations are essential for maintaining consistent database schemas across environments. While SQL-based migrations handle most scenarios effectively, Java-based Flyway migrations offer additional flexibility for complex data transformations, business logic integration, and operations that would be cumbersome in pure SQL.

However, testing these Java migrations presents unique challenges that we need to address to maintain reliable database evolution.

This article explores how to implement and test Java-based Flyway migrations in Spring Boot applications, covering isolation strategies and addressing common testing pitfalls.

Understanding Java-Based Flyway Migrations

Java-based migrations provide capabilities beyond what SQL migrations can offer.

We might choose Java migrations when we need to perform complex data transformations, integrate with external services during migration, or leverage existing business logic components. These migrations implement Flyway’s JavaMigration interface and execute within our application’s context.

Here’s a simple example where we need to populate a new field based on existing data:

This migration demonstrates a common scenario where we need to compute values based on existing data. While we could accomplish this with SQL, the Java approach allows us to leverage Spring’s JdbcTemplate for more robust database operations and potentially integrate more complex business logic when needed.

Let’s also create the foundation SQL migration that this Java migration builds upon:

The Challenge of Testing Java Migrations

Testing Java-based Flyway migrations presents several challenges that don’t exist with SQL migrations. The primary issue emerges when we use @SpringBootTest – Spring Boot automatically runs all migrations during application startup, including the Java migration we want to test.

This means our migration has already executed before our test code runs, making it impossible to verify the migration’s behavior properly.

Additionally, we often need to establish a specific database state before running our Java migration. We might need test data that represents the “before” state, allowing us to verify that our migration transforms the data correctly.

Testing Strategy: Controlling Migration Execution

To test Java migrations effectively, we need to control when Flyway executes our specific migration. We accomplish this by using Spring Boot’s Flyway configuration properties to limit which migrations run during application startup, then manually triggering our target migration within the test.

Here’s how we can structure an integration test for our Java migration:

The key elements of this testing strategy are:

  1. spring.flyway.target=1 – This property tells Flyway to only run migrations up to version 1, stopping before our Java migration
  2. Manual migration execution – We inject Flyway and call migrate() to run the remaining migrations, including our Java migration
  3. Before and after verification – We verify the database state before and after migration execution

Summary

Java-based Flyway migrations provide powerful capabilities for complex database transformations, but they require careful testing strategies. By controlling migration execution through Spring Boot properties and manually triggering migrations in our tests, we can verify that our Java migrations work correctly.

The key principles for testing Java migrations effectively are: limit initial migration execution using spring.flyway.target, establish the required pre-migration database state, manually execute the migration under test, and verify the results. While this approach requires fresh databases for each Flywyay test, it provides the isolation necessary to test migration behavior reliably.

Remember to implement checksum generation for Java migrations to help Flyway detect changes over time. Although testing Java migrations requires more setup than SQL migrations, the investment ensures that our complex database transformations work correctly across all environments.

Java migrations fill an important gap in database evolution capabilities, and with proper testing strategies, we can use them confidently to handle scenarios that would be difficult or impossible with SQL alone.

Joyful testing,

Philip

>