Vert.x and JUnit Testing
My experience with unit testing with either JUnit or TestNG is limited. With Domino development, business logic is often tightly coupled to accessing the underlying database. That makes automated testing a challenge. Similarly, the development of OpenNTF Domino API has been typically focused on code that interacts with the Domino server and databases, again making automated testing challenging. Where data persistence and the database-layer API is the main focus of the development, creating mock classes doesn't really bring much benefit. So it was Watson Workspace Java SDK which was my main experience of JUnit testing. Unit tests make a lot of sense where the business logic is about managing REST service access, both inbound and outbound.
The other reason unit testing was a good fit for Watson Workspace Java SDK was that it was added from the start of the development. The main benefit I can envisage for any test suite is to quickly validate refactored code. It's often said that good developers write less code, great developers remove code. If you've got a reproducible test suite, you can remove code and be certain you haven't broken anything.
Since I was last working with JUnit in depth, JUnit 5 has been released. JUnit 5 is the first major release since 2006, comprising JUnit Jupiter, JUnit Platform and JUnit Vintage. Because I'm working from scratch this time, JUnit Vintage isn't relevant. So far my testing hasn't worked much with JUnit Platform, for launching testing frameworks on the JVM. JUnit Jupiter is the core for any new tests but it also includes an extension model. Combining frameworks brings challenges and so an extension model makes that much easier. It's this extension model that Vert.x leverages to allow testing of its asynchronous verticles. Because otherwise JUnit would complete before awaiting responses. The Vert.x documentation identifies the extension to use and gives examples with the key annotation @ExtendWith(VertxExtension.class)
and VertxTestContext
class. The documentation also gives details of using JUnit 5 with Vert.x and there are also samples on GitHub. The key methods are VertxTestContext.succeeding()
which ensures JUnit runs asynchronously, VertxTestContext.verify()
which tests are wrapped in, and VertxTestContext.completeNow()
which is used to end the tests.
But as ever simplest is best. Depending on how the code is structured, it may be possible to test many methods without requiring asynchronous calls, separate from the Vert.x verticles that would typically be the entry point to them. This can be the case with classes for configuration objects, for example.
As will be seen from the Vert.x documentation for unit testing, the method described to make asynchronous calls to verticles is to use the io.vertx.ext.web.client.WebClient
class to make calls to a verticle that extends or is exposed via a Vert.x HTTP server. Typically this requires using DeploymentOptions
to ensure the HTTP server is exposed where the WebClient
is connecting. In many cases that may make sense to be done using an @BeforeEach
method. But there is another, newer way to run tests, a new module vertx-junit5-web-client
. This provides io.vertx.junit5.web.TestRequest
class and methods for making a request to a specific endpoint passing query parameters and header parameters and expecting certain outcomes. There is a blog post just a couple of months old, "Send web requests and assert results with vertx-junit5-web-client", the source as well as tests on GitHub. Obviously this is quite new, so not all documentation is available yet, but it is very useful for matching the response. However, as one would expect from a helper method, it doesn't give as much control as manually using a WebClient. It doesn't seem to allow parsing of the response, just comparing status codes or direct matching of the response, so it's best used when the exact response is known based on the request.
Of course it's also worth noting that the Vert.x classes I've mentioned for JUnit testing so far - WebClient
, TestContext
, TestRequest
- are using standard Vert.x classes. The documentation does also cover using VertxExtension.class
with the Vert.x wrappers for RxJava, both RxJava 1 and RxJava 2. In my case, because most modern makes sense, it will be RxJava 2. As with everything else, I expect more challenges and learning points when the need arises for writing JUnit tests for Vert.x verticles that use RxJava. But a hunger for learning and sharing is at the heart of my psyche.