Issue
How do i implement Fylway the correct way with Junit?
I added flyway to my project and put the V1__init.sql (for example) into main/resources/db/migration. As long as i debug my code (start it without test) it works.
Must i copy the *.sql files into test/resources/db/migration as well?
I also want, that the tests where made against another database, than test database. Am i correct, that i must add another application.properties under the testfolder where i put in the credentials for the buil-database (where the tests run against?).
Would be really happy if some one could help me out understanding how to configure it the right way.
Solution
You can leave the migration files under src and do not need to copy them to your test folder. They are gone be used when running a @SpringBootTest
. This also ensures that you are using all you production
migrations for our testing
Further you don't necessarily need a separate properties file for testing. But you can.
Following is an example for IntegrationTesting using TestContainers
which uses the application.properties
and also the flyway migrations because the test behave like you would normally run the application.
This is an abstract class which ensures that the tests are running in the whole Spring context so Flyway
is also involved. Within the initialiser the datasource configuration properties get override by the properties from the Database of TestContainers
. Doing that you directly use the real application.properties
and simulate a little bit the real ;))
@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers = AbstractPostgreSQLTestContainerIT.Initializer.class)
@Testcontainers
public abstract class AbstractPostgreSQLTestContainerIT {
private static final String POSTGRES_VERSION = "postgres:11.1";
public static PostgreSQLContainer database;
static {
database = new PostgreSQLContainer(POSTGRES_VERSION);
database.start();
}
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
configurableApplicationContext,
"spring.datasource.url=" + database.getJdbcUrl(),
"spring.datasource.username=" + database.getUsername(),
"spring.datasource.password=" + database.getPassword()
);
}
}
}
Now you can define your several test classes like following:
class MyIntegrationTest extends AbstractPostgreSQLTestContainerIT { }
When running the tests inside this class the SpringBoot application starts and uses the TestContainers
database.
For my purpose I have also implemented a simple annotation:
@TransactionalSQLTest("classpath:db/test/create_base_foo_data.sql")
void updateFooByExternalIdentifier_DTOProvided_ShouldReturnUpdatedFoo() {}
Code
/**
* Annotation which allows to provide SQL Scripts for a certain IT test.
* The transactional ensures that data is cleaned up after test.
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional
@Test
@Sql
public @interface TransactionalSQLTest {
@AliasFor(attribute = "value", annotation = Sql.class)
String[] value() default {};
@AliasFor(attribute = "executionPhase", annotation = Sql.class)
Sql.ExecutionPhase executionPhase() default Sql.ExecutionPhase.BEFORE_TEST_METHOD;
}
Using the annotation you can provide the SQL with e.g. sample data for your test.
The pom.xml
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
This should be the dependency for MySql
<!-- https://mvnrepository.com/artifact/org.testcontainers/mysql -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>
<version>1.15.3</version>
<scope>test</scope>
</dependency>
Answered By - Daniel Wosch
Answer Checked By - Mary Flores (JavaFixing Volunteer)