08. February 2021
8 min

Testing Quarkus with Kotlin, JUnit and MockK

Want to get some practical insights how to mock CDI beans in your Quarkus tests written in Kotlin? In this blog post we show you how we realized it with JUnit and MockK.
Testing Quarkus with Kotlin, JUnit and MockK

The rather young framework Quarkus becomes more and more a serious competitor to established microservice frameworks such as Spring Boot. This is largely due to the fact that the powerful but yet lightweight application framework offers small memory footprint and reduced boot time. And it is tailored for the JVM as well as Oracle’s GraalVM. Hence it’s not only interesting for developing microservices in containerized cloud platforms such as Kubernetes, but also for serverless computing.

When developing applications with Quarkus you will eventually have to write (unit) tests to determine whether your code behaves as expected. In this post I will give you an insight how to use JUnit and MockK to create isolated Quarkus tests with mocked CDI beans.

Table of contents

TLDR: How to mock your Quarkus CDI beans with JUnit and MockK

You are already familiar with Kotlin, Quarkus, JUnit and MockK and just need a practical code example? Here you go:


The example above, which can be found on GitHub, shows how within the RestControllerTests class the CDI bean MainService is mocked and a specific behaviour is defined. 

If, however, you are interested in some more details and further Kotlin implementations, then please continue reading.

Quarkus and Kotlin

In the last few years Kotlin could establish itself as a popular alternative to Java. Although it had its first breakthrough in Android development, it’s now widely used in the JVM backend world. This is reflected as almost all relevant frameworks support Kotlin as a first-class language (e.g. Spring, Micronaut, Vert.x, Javalin, http4k, Ktor, etc.). And so does Quarkus! See this blog post for a first introduction.

So if you have the possibility to choose between Java and Kotlin as a backend developer – I would always recommend picking Kotlin! The reasons for this are – besides the more expressive and concise syntax – the numerous modern language features it provides, e.g. Null Safety, Data Classes, Multiline String Literals, String Templates, Extension Functions and Coroutines.

Why should you use JUnit and MockK to write tests?

Alrighty then, you have decided to create an application with Quarkus and Kotlin. Great choice!

Sooner or later (hopefully sooner 😉 )  you need to take care of writing tests. And you choose a test framework for that. JUnit is pretty common in the JVM world and I have used it successfully in several contexts with different application frameworks. And at least since JUnit 5 was released I’m really pleased to use it with its excellent Kotlin support. 

When writing tests at some point you commonly have to mock parts of your application. E.g. if you test a RestController you might want to mock the underlying Service.
As a Java developer you are probably familiar with
Mockito, a well established and powerful tool to create mocks in unit tests. Although there are enhancements to use Mockito with Kotlin it was primarily built for Java and therefore has certain limitations. If you want to use the full potential of Kotlin for mocking, MockK is the better option. It was designed from scratch for Kotlin and therefore doesn’t need some “hacks” that are necessary in Mockito for Kotlin. For instance, mocking a final class (all classes in Kotlin are by default final) is easier with MockK.

Mocking Quarkus CDI beans with MockK

But enough opening words – let’s have a look at the implementation. Imagine a very basic application like this:

Example of Quarkus app

There’s a RestController which handles HTTP calls and delegates to an underlying MainService. The MainService itself has a dependency to a SubService.

Note: The whole example can be found on GitHub, where you can also easily check which Gradle/Maven dependencies are needed.

Mocking a Service call

First of all let’s have a closer look at the MainService:


And this is the Kotlin implementation of the SubService:


In line 3 the SubService CDI bean is injected into the MainService via Constructor Injection. With calling the MainService’s function sayHello() the implementation returns “Hello from the REAL MainService – Hello from the REAL SubService”.

It’s very important to define the services as normal scoped CDI beans – the most common of which are @ApplicationScoped and @RequestScoped. Beans annotated with @Singleton or @Dependent scope cannot be mocked with QuarkusMock which will be used later on. For details please refer to the Quarkus documentation.

To test the MainService a JUnit test is created: 


This is a very basic unit test where the “testeenamely the MainService – is simply instantiated (line 5). And the mocked SubService, which was declared in line 3, is passed as a parameter.

The test itself (line 7-14) follows the AAA pattern: Arrange-Act-Assert

In the first step the mock’s behaviour is arranged. One of the big advantages of MockK is its easy readable DSL: You can clearly see that line 9 defines that every call of the mocked SubService function sayHello() should return “Hello from MOCKED SubService”.

In the next step  – the Act section – the actual method call is executed.  And finally the result is verified by an AssertJ assertion. 

For this basic example such a plain unit test without any “Quarkus framework magic” is absolutely sufficient. Job done!

But what if there are framework features or annotations within your service which should be validated by the test as well? For example, we had the situation where a service function needed to be cached and therefore was marked with Quarkus’ own @CacheResult. And a test should validate that caching works correctly. In this case a plain unit test is no longer adequate – you need Quarkus to be started for your test execution.

This means you need some kind of test extension that starts Quarkus and keeps it running for the duration of the test run. Luckily with quarkus-junit5 comes @QuarkusTest – which does exactly that.

In line 3 of the following – let’s call it “Int-Test” – you can see how this annotation is applied:


The declaration @TestInstance(PER_CLASS) configures JUnit to create only one instance of the test class and reuse it between tests. The default would be PER_METHOD, but that requires the setupMocks() function in line 8-10 to be static as it is annotated with @BeforeAll. And static behaviour in Kotlin is handled differently than in Java.

In chapter “Other possible Kotlin implementations” I will show different ways to specify this JUnit behaviour with Kotlin, e.g. with a companion object or by utilizing @BeforeEach. Please have a look at them, too, perhaps they fit better to your personal coding style.

In line 1 MockK is used to create a mock for the SubService. Within the setupMocks() function the utility class QuarkusMock applies this mock. More precisely, the method installMockForType() installs the mock for the specified CDI bean.

Note: The “old approach” to create mocks in Quarkus tests by adding the annotation @Mocks leads to several problems. The most significant is that such a mock defined in one test class influences the behaviour of other test classes, which breaks the golden rule of testing: tests must be independent of each other. Therefore using QuarkusMock is the recommended approach.

The MainService as “testee” is declared in line 12-14. The @field: Default is needed to make CDI’s @Inject work with Kotlin as it has no @Target on the annotation definition (see https://quarkus.io/guides/kotlin for details).

The actual test in line 16-23 is similar to the one in the previous basic unit test.

Mocking Beans in a RestController

So far, so good. By mocking the SubService we could test our MainService isolated from its dependencies. But what about the RestController?

As as start let’s have a look at the implementation:


The MainService bean is injected in the class’s constructor. The function in 6 -11 defines that when calling the endpoint /hello with the HTTP verb GET this response is returned:


To test your RestController isolated from the underlying MainService a test class like this is required:


Defining and applying the mock is equivalent to what was described in the previous chapter (line 1 and line 8-10).

This is followed by two tests:
The first test (line 12-25) validates that a (mocked) result from the MainService is correctly serialized to JSON. To call the /hello endpoint and validate the outcome RestAssured is used.

The second test in line 28-35 checks that if the mocked MainService throws an exception the RestController returns the status code 500 (Internal Server Error).
To be honest – testing if Quarkus maps a RuntimeException to the status code 500 is obviously pretty useless. This example is vastly simplified. However you could want to test if user defined exceptions are mapped to certain status codes, e.g. something like a UserNotFoundException to status 404 or an OptimisticLockException to status 409.

Other possible Kotlin implementations

As mentioned previously the usage of @TestInstance(PER_CLASS) is not the only way to specify JUnit’s behaviour. I personally like the short and concise way it offers to declare and apply the CDI bean mocks. Nevertheless there are (at least) two more options to be mentioned:

Using a companion object

As the main problem is that @BeforeAll in combination with @TestInstance(PER_METHOD) needs a static method you can move the function setupMocks() to a companion object and annotate it with @JvmStatic.


In addition this allows you to declare your mock within the same companion object, so mock declaration and application are in the same scope of your code.

Using @BeforeEach

Of course you can use @BeforeEach instead of @BeforeAll as this doesn’t require a static method:


This means that the mock is (re-)declared and applied before each test. Therefore if you have many mocks and even more tests this might somewhat impact your test execution time.

Unsolved issues

So far we have discovered two points you should be aware of:

Mocking RestClients

If you try to mock a bean that is declared as @RegisterRestClient the mocking fails.
This means when you inject such a bean with @RestClient in a service and try to install a mock in the corresponding test class you get an exception like this when executing the test:


A colleague of mine has opened an issue for this and it looks as if the Quarkus team is already on it.

Using @Nested Inner Classes

When using Kotlin and JUnit it is a common practice to structure your test classes with @Nested Inner Classes. For example you could structure your RestController test like this:


Unfortunately this structuring doesn’t work in tests that are annotated with @QuarkusTest. Although the usage of JUnit’s @Nested in Java seem to work for Quarkus, the combination with Kotlin’s Inner Classes still causes difficulties. 

Conclusion

Testing is a crucial part of application development, no matter what framework, language or library you use. Personally I am a big fan of Kotlin. And Quarkus offers – beneath its Kotlin support – a “best breed of libraries and standards”. Thus I think it is an excellent choice. Together with JUnit and MockK, efficient testing is not only possible but also fun.

What are your experiences with Quarkus, Kotlin, JUnit and MockK? Or what is your answer to the ultimate question of testing, the universe, and everything. Leave a comment, I will try to get back to you.

Comment article

Comment