Nov 16, 2021

Testing a Quarkus Kafka Application

Quarkus, a “Kubernetes Native Java stack,” enables lighter Java applications with faster startup times. In a recent post, I talked about scaling Kafka consumers in Kubernetes. Quarkus applications fit right into this picture because they have –

  • Smaller build images, which optimizes container pull times.
  • Lower memory utilization, which optimizes container density.
  • Faster startup times, which enables extremely responsive auto-scaling.

This sounds great, let’s check it out.

Local Kafka Development

When setting up your Quarkus application, there are a few supported Kafka Quarkus extensions.

  1. Apache Kafka Client (Consumer/Producer API)
  2. Apache Kafka Streams (Streams API)
  3. SmallRye Reactive Messaging

Quarkus starts Dev Services for Kafka alongside the application when running the dev or test profiles if any of the above Kafka extensions are found. Dev Services utilize Testcontainers (Docker) and runs the Vectorized Redpanda image due to faster startup times. Being that Redpanda is only “Kafka compatible”, I prefer to run my own local Kafka environment. Confluent has published a great set of local environment examples here.

Dev Services can be disabled explicitly via the quarkus.kafka.devservices.enabled property or implicitly by pointing the kafka.bootstrap.servers property to your own Kafka brokers.

It’s painless to get a local application running and connected to Kafka. The Quarkus blog has a variety of posts to get you moving towards your goals.

In exploring the Spring Boot alternative landscape, the guides tend to focus on ease of adoption instead of the quality of adoption. The rest of this post will look at a few options for testing a Quarkus application that’s integrated with Kafka.

Quarkus Test Framework

Quarkus is clearly proud of the startup times, so it starts itself up by default for tests. The @QuarkusTest annotation that you put on each test class is more or less the equivalent of @SpringBootTest. Each test has everything wired up and available for injection.

My first reaction to this was not positive due to a bumpy history with @SpringBootTest. However, Quarkus makes it easy to put @Alternative implementations of commonly mocked layers into the CDI. The use of @Alternative and @Mock results in global mocks for all test cases. You can also use @QuarkusMock for mocks that are scoped to a single test.

The testing framework is documented pretty well here. However, your tests are also going to need Kafka brokers started up for them to execute. This is where things get a little more interesting.

Quarkus Test Resource

The @QuarkusTestResource annotation makes it easy to start any dependent service that the application needs. Point the annotation to an implementation of QuarkusTestResourceLifecycleManager and it will start/stop the resource before/after tests execute.

If you are running locally against a Docker environment, it makes sense to run a similar environment for tests via Testcontainers. However, there are times where running tests against Docker may not be ideal or even possible. For this reason, there is also an embedded option that may be best.

Both of these are illustrated below.

Dockerized Test Resource

First, define the Test Resource. This example is using Testcontainers Kafka Module.

Next, as a nicety, create a custom annotation to simplify how tests designate that they want Kafka available. This also includes the @QuarkusTest annotation so that you only need a single annotation on your test class instead of multiple. You’ll notice there is also the use of @DisabledIfSystemProperty. This is a simple option for only running these tests in “container enabled” environments.

Lastly, apply the new annotation to your tests.

Embedded Test Resource

If you’re using SmallRye, there is an embedded messaging option available and detailed here. If you’re not, there are a few embedded broker options out there. The following example is using the Spring Kafka Test embedded broker.

Similar to the previous example, we first define the Test Resource.

Next, we define a custom annotation to condense the testing annotations.

Lastly, apply the new annotation to your tests.

Conclusion

Quarkus is being assessed and adopted as an alternative to Spring Boot due to smaller images and faster startup times. If you join the crowd and decide to assess Quarkus, be sure to build in time for quality up front!

About the Author

Matt Schroeder profile.

Matt Schroeder

Director, Modern API

A wide range of professional experience and a Master’s Degree in Software Engineering have become the foundation that enables Matt to lead teams to the best solution for every problem.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Retrofit2: Get the body from an error response
Retrofit2 is a nice library for making HTTP rest requests. It includes a static utility (CallUtils) for getting the result from your request, but if the api you’re calling doesn’t return a 2xx request it […]
Airflow Logging: Task logs to Elasticsearch
This is part three of a five-part series addressing Airflow at an enterprise scale. I will update these with links as they are published. Airflow: Planning a Deployment Airflow + Helm: Simple Airflow Deployment More […]
Using Nix as a Professional
How to use Nix as a tool to optimize developer time with real-life examples.
Enterprise Auth for Airflow: Azure AD
This is part three of a five-part series addressing Airflow at an enterprise scale. I will update these with links as they are published. Airflow: Planning a Deployment Airflow + Helm: Deploying the Chart Without […]