I'm trying to write integration tests for our application and I've hit a roadblock I can't seem to overcome.
I've set my test resource
@Slf4j
public class PostgreSQLTestResource implements QuarkusTestResourceLifecycleManager {
private static PostgreSQLContainer<?> postgreSQLContainer;
@Override
public Map<String, String> start() {
log.info("Starting PostgreSQL with profile: {}", System.getProperty("quarkus.profile"));
postgreSQLContainer =
new PostgreSQLContainer<>("postgres:alpine")
.withDatabaseName("test")
.withUsername("postgres")
.withPassword("password")
.withReuse(true);
postgreSQLContainer.start();
Map<String, String> config = new HashMap<>();
config.put("quarkus.datasource.jdbc.url", postgreSQLContainer.getJdbcUrl());
config.put("quarkus.datasource.username", postgreSQLContainer.getUsername());
config.put("quarkus.datasource.password", postgreSQLContainer.getPassword());
config.put("quarkus.liquibase.jdbc.url", postgreSQLContainer.getJdbcUrl());
log.info("JDBC URL: {}", postgreSQLContainer.getJdbcUrl());
return config;
}
@Override
public void stop() {
if (postgreSQLContainer != null) {
postgreSQLContainer.stop();
}
}
}
The test itself:
@QuarkusTest
@TestProfile(TestProfileResolver.class)
@QuarkusTestResource(value = PostgreSQLTestResource.class,restrictToAnnotatedClass = true)
public class XServiceTest {
@Inject
XTypeVersionService xTypeVersionService;
@BeforeEach
void setUp() {
closeable = MockitoAnnotations.openMocks(this);
}
@AfterEach
void closeMocks() throws Exception {
closeable.close();
}
...
@Test
void getXTypeVersion() {
List<XTypeVersionEntity> guh = xTypeVersionService.get();
assertTrue(!guh.isEmpty());
}
}
And
public class TestProfileResolver implements QuarkusTestProfile {
@Override
public String getConfigProfile() {
String activeProfile = System.getProperty("quarkus.profile");
log.info("Active profile: {}", activeProfile);
return "test";
}
@Override
public Map<String, String> getConfigOverrides() {
String configLocation = System.getProperty("quarkus.config.locations");
log.info("Config location: {}", configLocation);
if (configLocation == null || configLocation.isEmpty()) {
log.info("Setting config location to src/test/resources/application.yaml");
return Map.of("quarkus.config.locations", "src/test/resources/application.yaml");
}
return Collections.emptyMap();
}
}
And the test profile properties:
quarkus:
profile: test
http:
test-port: 9300
datasource:
db-kind: postgresql
jdbc:
url: jdbc:tc:postgresql:alpine://test?TC_INITSCRIPT=init.sql
driver: org.testcontainers.jdbc.ContainerDatabaseDriver
hibernate-orm:
database:
generation: drop-and-create
liquibase:
enabled: true
migrate-at-start: true
change-log: classpath:db/dbChangelog-test.yaml
default-schema-name: x
validate-on-migrate: true
jdbc-url: jdbc:tc:postgresql:alpine://test?TC_INITSCRIPT=init.sql
log:
min-level: DEBUG
category:
"io.quarkus":
level: INFO
"org.testcontainers":
level: INFO
"liquibase":
level: TRACE
The problem is that it looks like the Liquibase scripts are being executed but the tests don't work. Meaning the test to get all x types fails because it can't find any. Digging deeper I notice that when I execute the test, 2 Postgres containers are created and shown in the docker desktop app. It is also corroborated in the console output where I can see 2 jdbcs that look similar but have different ports. I believe that the Liquibase script is being executed in one container and the application is accessing the second one.
Has anyone had an issue like this or better yet a working example of test containers with Liquibase (and better yet, using Quarkus)?
The reason why there are 2 postgres instances spinned up is, because Quarkus also does that for you automatically when you’re running in the test and dev profiles.
You don’t need to explicitly create a QuarkusTestResourceLifecycleManager
. As a matter of fact, you don’t need to specify your db url and do anything with Testcontainers.
Just write your test and a db is automatically spinned up for you. You don’t have to configure anything, this is all handled.
So you can remove all your code, except your test class and then it should look something like this:
quarkus:
http:
test-port: 9300
datasource:
db-kind: postgresql
hibernate-orm:
database:
generation: none <--> drop-and-create is going to conflict with liquibase
liquibase:
enabled: true
migrate-at-start: true
change-log: classpath:db/dbChangelog-test.yaml
default-schema-name: x
validate-on-migrate: true
// quarkus will spin up postgres automatically from here
@QuarkusTest
@TestHTTPEndpoint(YourRestController.class) ---> this will automatically add the rootpath to RestAssured
class MyTest {
...
}
For more info check these links: