Simply start and stop Jakarta EE containers and deploy applications for your integration tests. This is an extension to Testcontainers for Jakarta EE application servers, so Docker is used under the hood, but you don’t need to write, e.g., a Dockerfile.
Prototypical Example:
@Testcontainers
public class MyAppIT {
@Container static JeeContainer CONTAINER = JeeContainer.create()
.withDeployment("target/my-app.war");
@Test void shouldGetStatusResponse() {
String body = CONTAINER.target().request(APPLICATION_JSON_TYPE).get(String.class);
then(body).isEqualTo("{\"status\":\"okay\"}");
}
}
Or if you have an implementation of Microprofile Rest Client on your test classpath:
@Testcontainers
public class MyAppIT {
@Container static JeeContainer CONTAINER = JeeContainer.create()
.withDeployment("target/my-app.war");
@Data public static class Status {
String condition;
}
public interface StatusApi {
@GET Status getStatus();
}
@Test void shouldGetStatusResponse() {
StatusApi body = CONTAINER.restClient(StatusApi.class);
Status status = body.getStatus();
then(status.getCondition()).isEqualTo("okay");
}
}
The console output of the container is piped to the test’s output, STDOUT in green and STDERR in blue.
As seen in the prototypical example above, you can install an application by calling .withDeployment(<file>)
.
Instead of a local file, you can also install from an URL.
Or you can use a maven URN like urn:mvn:org.jolokia:jolokia-war-unsecured:1.6.3:war
.
Set the system property jee-testcontainer
to one of the keys in the following table to select the corresponding container.
Ideally you shouldn’t have to care about what server your application runs on, or you may even want to test it in multiple containers.
Then you can run your test suite in your CI pipeline with different system properties.
You can append a tag to the jee-testcontainer
separated by a colon :
.
This is often simply the version of the container; e.g. wildfly:27.0.0.Final
.
Key | Container | Docker Image | Notes |
---|---|---|---|
|
default container on |
||
|
we add |
||
|
Official image |
||
|
not an 'official' image on Docker-Hub |
You can reuse a running container instance for all tests as long as the config doesn’t change, by calling withReuse(true)
.
This feature is marked as unstable from testcontainers.org.
You can achieve the same by setting the system property testcontainer-reuse
to true
, which comes in handy when you need it only for certain launch configurations, i.e. local or on CI.
By default, the main port exposed by the container (which accidentally is 8080 in all currently supported JEE servers) is published/bound to a random free port.
You can bind it to a fixed port by calling JeeContainer#withMainPortBoundToFixedPort(int hostPort)
.
Or you can set the testcontainer-with-main-port-bound-to-fixed-port
system property for the same effect.
Similarly, you can publish any port by calling JeeContainer#withPortBoundToFixedPort(int hostPort, int containerPort)
.
Fixing port numbers may be convenient in some cases, but you shouldn’t do this without a good reason.
You can modify the deployable in two ways. You can have multiple and repeated modification to, e.g., rename the file and add multiple libraries.
import static com.github.t1.testcontainers.jee.NamedAsMod.namedAs;
@Testcontainers
public class MyAppIT {
@Container static JeeContainer CONTAINER = JeeContainer.create()
.withDeployment("target/my-app.war", namedAs("foo.war"));
}
import static com.github.t1.testcontainers.jee.AddLibMod.addLib;
@Testcontainers
public class MyAppIT {
@Container static JeeContainer CONTAINER = JeeContainer.create()
.withDeployment("target/my-app.war", addLib("urn:mvn:org.jolokia:jolokia-war-unsecured:1.6.3:war"));
}
import static com.github.t1.testcontainers.jee.ConfigMod.config;
@Testcontainers
public class MyAppIT {
@Container static JeeContainer CONTAINER = JeeContainer.create()
.withDeployment("target/my-app.war", config("foo", "bar"));
}
Configure the MP Config key foo
to be bar
.
Creates or appends to WEB-INF/classes/META-INF/microprofile-config.properties
.
You can configure the log level of a logger, e.g. by calling withLogLevel
(at the moment, this only works for WildFly containers, but we’re open for PRs 😀).
You can also configure a data source by calling withDataSource(DB)
, where DB
is a JdbcDatabaseContainer
(currently only PostgreSQLContainer
and only on WildFly
).
For WildFly
, you can also call arbitrary CLI
commands by calling withCli
.
Apart from that, you can’t currently configure anything else for your application, e.g. add message queues. I will add such things whenever I need it, but again: PRs are welcome.
There’s a very limited support to build a war
deployable from scratch.
See the API of the DeployableBuilder class for details.
If you need more, maybe ShrinkWrap can help, but I haven’t tried that in combination, yet.