Recently, we had a discussion how to create a standalone Jakarta Batch test kit (TCK). For most of the committers, it’s pretty natural to use Arquillian to abstracts tests away from how they are executed on an implementation. But Romain proposed an intriguing idea to use plain JUnit5 that got me thinking. And it didn’t stop with thinking. After a few hours of hacking, I’m now able to present a proof of concept and suggest how we could use plain JUnit5 for the TCK and also how containers can be integrated with it using good old Arquillian to avoid reinventing the wheel.
UPDATE: The Arquillian project has moved forward and it now supports JUnit5 with an official extension. This makes it even easier to combine Arqullian with JUnit5. I’ve updated my article to refer to this official extension.
The problem with the current standalone Batch TCK is that it’s based on TestNG and only supports Batch implementations that run on the same classpath as the test suite. Therefore it doesn’t support running tests in Java containers like application servers. Such containers are now supported only by the Jakarta test suite (CTS) which contains a copy of Batch TCK tests uses a proprietary technology to run tests in containers.
There are other Jakarta EE specifications with a standalone TCK or with plans to create it:
- CDI TCK – uses TestNG with Arquillian
- Bean Validation – uses TestNG with Arquillian
- JSON-B – in progress, uses JUnit 4 with Arquillian
- DI TCK – JUnit 4
It’s clear that Arquillian is pretty popular among them. Only DI TCK doesn’t use it. But DI TCK also doesn’t support execution in a remote container natively, it only supports setting up a local container, e.g. using the CDI SE API if the implementation supports it.
I had 3 goals with my proof of concept:
- improve the TCK to make it possible to integrate with a Java container
- adapt the existing example project to run JBatch with the TCK
- create another example of integrating the TCK with a typical Jakarta EE server such as Payara Server
I prefer gradual evolution rather than big bang development if it makes sense. And I realized that I will probably need Arquillian to integrate with Payara Server for my third goal anyway, even if I find a solution using JUnit 5. So I started with adding support for Arquillian into the current Batch TCK and later I hoped to reuse it to integrate Payara Server with JUnit 5. It turned out that it was a good approach and no code went to waste.
Adding support for Arqullian
Adding support for Arquillian into the Batch TCK was pretty straightforward because the tests already use TestNG and Arquillian supports TestNG out of the box. The only tricky part was to create a deployment package for each test which is required by Arquillian. In the end, this was pretty easy and required no modification of the test sources. Arquillian allows to create an extension to define a deployment package for each test so I was able to move creation of a deployment package to a separate extension. This extension can be used by implementations that need to run the tests in a container but it’s not needed in the TCK itself.
The only change needed in the TCK was to change each test to extend the Arquillian TestNG base class and that was it.
On top of the test suite, the Batch TCK contains an example TCK runner project that runs the TCK against the JBatch implementation. This also needed to be changed slightly. I added Arquillian Weld SE connector, which runs the Arquillian TestNG tests in a Weld CDI container. This means the tests are executed on the same classpath as the test suite and no Arquillian deployment is needed.
You can see the end result in my fork here: https://github.com/OndroMih/batch-tck/pull/4. In summary, I added a single line of code to each TCK test and modified pom.xml of the Batch TCK and the TCK runner for JBatch.
This allowed me to create an example project for running the TCK with a remote server like Payara Server. This example project contains the Arquillian extension I mentioned above. This extension uses Maven resolver library to resolve JAR dependencies from the project’s pom.xml file and package them into a WAR deployment for Arquillian. It’s not complicated, it requires just a few lines of code: MavenTestDependenciesDeploymentPackager.java
Converting the TCK to JUnit5
Converting a TestNG-based TCK to JUnit 5 was pretty straightforward. Besides replacing all TestNG annotations with JUnit 5 equivalents, I also needed to replace TestNG reporting with the standard Java JUL logging. At that time, I didn’t know that JUnit 5 also supports reporting from tests via TestReporter. For a final solution, I would use that instead of JUL logging.
You can see the final result of my conversion here: https://github.com/OndroMih/batch-tck/pull/3. The TCK is changed and the JBatch runner project also uses it and runs without test failures. This solves my first 2 goals.
The hardest thing was to connect a JUnit 5 test suite with Payara Server to meet my 3rd goal. For that, I needed to solve the following problems:
- create a deployment package to deploy tests to Payara Server
- create a JUnit 5 extension to run the tests in Payara Server and report the results back
I already solved the first problem with an Arquillian extension in the previous step. And it seems there’s an unofficial JUnit 5 extension to run Arquillian tests. And yes, it worked, I was able to merge all this to a final solution for all of my 3 goals.
Running the JUnit 5 TCK with Arquillian
Luckily, the Arquillian community has been working on support for JUnit 5. Although this effort was stuck for a while waiting for an essential extension point only added in JUnit 5.5, there’s now an unofficial arquillian-junit5-extension with some fixes in this fork.
UPDATE: Arquillian now provides an official JUnit 5 extension, which can be used instead. It’s based on the unofficial extension that I used but is available in Maven Central and contains some additional fixes.
So I tried to pull all what I already had together to try if I can get the converted JUnit 5 Batch TCK running against Payara Server:
- use the JUnit 5 Batch TCK as a dependency
- add the arquillian-junit5-extension
- add the Arquillian deployment extension I created earlier
- configured Arquillian to run with the Payara connector as I did earlier
So I did it, started Payara Server, configured the necessary JDBC resources, and executed the following:
… and prayed.
After a few minues:
Tests run: 164, Failures: 0, Errors: 0, Skipped: 3
All worked! This includes all TCK tests, including the tests that require other Jakarta EE functionality and which are not run for standalone Batch implementations like JBatch. Those 3 skipped tests are currently being skipped by the TCK and not by my configuration.
I was able to demonstrate there are multiple ways to improve existing standalone Jakarta EE TCKs or create new ones from the full Jakarta CTS suite in a modern way.
One of them is an already proven way of adding Arquillian into a JUnit 4 or TestNG test suite and expect that all implementations provide an Arquillian container to run the tests with them. As demonstrated, this is pretty easy with a few lines of code, writing a simlple Arquillian extension to define deployments for all tests.
But there’s also an interesting new way which uses JUnit 5, one of the most modern test frameworks for Java. JUnit 5 provides enough extension points and also allows enabling extensions globally for all tests. This means that the tests don’t need to include any boiler-plate code required to enable the extensions. Implementers can use Arquillian to run the tests via an existing JUnit 5 Arquillian extension once it’s officially released, or they can create their own JUnit 5 extension to connect the tests with their implementation. Or they are free to use the existing unofficial JUnit 5 Arquillian extension already and even modify it if needed because they can really use anything they want.