Quarkus and Testcontainers
If you did not know Quarkus, here is an introductory article: Zoom sur Quarkus (french).
Quarkus offers Unit Test (TU) support with JUnit 5 via the @QuarkusTest
annotation, documentation for Quarkus TU support can be found here.
Here is an example of a TU from the Hibernate ORM Quickstart :
@QuarkusTest public class FruitsEndpointTest { @Test public void testListAllFruits() { given() .when().get("/fruits") .then() .statusCode(200) .body( containsString("Cherry"), containsString("Apple"), containsString("Banana") ); } }
Conventionally, you can run tests using an embedded database, Quarkus supports the H2 BDD for that. But if we want our tests to run in an environment as close as possible to production, the use of the same database is better.
We would therefore like to be able to use a Postgres database to run our tests.
Testcontainers is a library that allows you to easily start a Docker container within your TUs. It provides a JUnit 5 extension and an extension to easily launch databases. Its use would therefore be ideal for launching a Postgres database for our TUs.
The classical integration of Testcontainers is done via the @Testcontainers
annotation which allows to start the JUnit 5 extension for Testcontainers and allows to start containers via @Container
, see the documentation of the Junit 5 extension of Testcontainers.
The issue is that the two extensions, the Quarkus one and the Testcontainers one, do not work very well together because Quarkus will start before Testcontainers and the container will not be started before the Quarkus application starts. The database will therefore not be started when your application starts, so your application will fails to start.
With JUnit 5, we should be able to order the extensions between them via @ExtendWith
but it is not possible to use this annotation with Testcontainers (more info here).
The solution ? Using a modified JDBC URL for Testcontainers (documented here ).
For our example we must first add the Testcontainers dependencies to our pom.xml
.
<dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</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> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency>
Then add the annotation @Testcontainers
to our FruitsEndpointTest
.
Finally configure our datasource via our application.properties
using a modified JDBC URL for Testcontainers:
quarkus.datasource.url = jdbc:tc:postgresql:11.3://hostname/mydatabase quarkus.datasource.driver = org.testcontainers.jdbc.ContainerDatabaseDriver quarkus.hibernate-orm.dialect = org.hibernate.dialect.PostgreSQLDialect
Attention, you must then specify the Hibernate dialect because the automatic dialect selection does not work when the JDBC URL is modified.
Once all this is configured, when Quarkus initializes its datasource, Testcontainers will automatically start a Postgres container and you will see the following lines in your logs:
2020-02-17 15:03:20,078 INFO [org.tes.doc.DockerClientProviderStrategy] (Agroal_5751340441) Loaded org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy from ~/.testcontainers.properties, will try it first 2020-02-17 15:03:20,283 INFO [org.tes.doc.EnvironmentAndSystemPropertyClientProviderStrategy] (Agroal_5751340441) Found docker client settings from environment 2020-02-17 15:03:20,283 INFO [org.tes.doc.DockerClientProviderStrategy] (Agroal_5751340441) Found Docker environment with Environment variables, system properties and defaults. Resolved dockerHost=unix:///var/run/docker.sock 2020-02-17 15:03:20,374 INFO [org.tes.DockerClientFactory] (Agroal_5751340441) Docker host IP address is localhost 2020-02-17 15:03:20,390 INFO [org.tes.DockerClientFactory] (Agroal_5751340441) Connected to docker: [...] 2020-02-17 15:03:20,958 INFO [org.tes.DockerClientFactory] (Agroal_5751340441) Ryuk started - will monitor and terminate Testcontainers containers on JVM exit 2020-02-17 15:03:20,970 INFO [🐳 .3]] (Agroal_5751340441) Creating container for image: postgres:11.3 2020-02-17 15:03:21,009 INFO [🐳 .3]] (Agroal_5751340441) Starting container with ID: c40f75e48f238f2aafe14899adae0afd3a3948396c19247aff64811166d4b057 2020-02-17 15:03:21,390 INFO [🐳 .3]] (Agroal_5751340441) Container postgres:11.3 is starting: c40f75e48f238f2aafe14899adae0afd3a3948396c19247aff64811166d4b057 2020-02-17 15:03:23,038 INFO [🐳 .3]] (Agroal_5751340441) Container postgres:11.3 started in PT2.067585S