I have been working with Kotlin a lot lately. It is a really awesome language. Elegant, powerful and succinct, it fixes most of the annoyances that I had with Java, yet it keeps a certain amount of familiarity that allows the transition from it to be very manageable.
Anyhow, I found myself recently having to build a filter in SpringBoot that I wanted to test. For that I needed to use both a mock and verify that behavior at the same time. Kotlin is evolving quite fast and there are plenty of alternatives to choose from. I will show how to do this with two excellent libraries, MockK, and Atrium.
MockK and Atrium, a powerful combo
In the short time that I have been developing Kotlin, I’ve noticed a pattern. Whenever you need something not provided in the standard library, you tend to start by using the existing Java library that you are familiar with. Then, at some point, you figure out there is a native Kotlin library that leverages the features from the language better.
MockK seems to be on its way to become the defacto mocking library for Kotlin apps. With a syntax based heavily around lambdas, it just looks like a DSL, as you can see in this example taken directly from their page:
Meanwhile, Atrium is less established, but after getting the recommendation from a colleague, I gave it a try. It uses
expect, so for somebody like me who is used to RSpec it is already a win. Anyhow, the syntax takes some time to get used to, but it can be quite expressive. I particularly like combining it with data classes to have exactly one assertion per test instead of many.
The problem at hand
What I was trying to build was not particularly complex. I wanted to write a filter for a SpringBoot application that would inject some headers into the request based on some logic. All controllers would use these values transparently, without having to care about the computation. The filter looks like this.
I want to test two things:
filterChainshould be called with my
wrappedRequestshould have the correct header in it
Setting up the test
I am using annotations to initialize the mocks (which requires annotating the test with
filterChain is a
RelaxedMockK, which means that its methods will return a default value unless otherwise specified.
A very simple test
If I just want to check that the method is being called, I don’t really need much
Testing the wrapped request
The previous test is OK, but it is a bit bland for my taste. I want to make sure that that the
filterChain is being called with my
wrappedRequest, and that it contains the header I injected. This test becomes much more interesting
Not so simple anymore! Let’s break it down.
First we are capturing the first argument for
doFilter (i.e: the wrapped request). We are creating a new slot by doing
slot<ServletRequest>, and capturing it by passing it in the
verify block by doing
let block wrapping everything is there so that we don't need an extra local variable (and to feel more kotlin-y inside).
After all this
slot.captured contains the
wrappedRequest that we created in the filter. Here is where Atrium can shine. We use
isA first to check that the request is of the right type. Then inside the block
subject is the casted type, where we finally check that our header is there.
With this our small filter can be tested properly and with very little overhead. I am no Kotlin connoisseur, but the syntax of both MockK and Atrium feels quite elegant to me, once you wrap your head around it. I think this is a good starting point to build better and better tests without a ton of boilerplate code.
Originally published at https://hceris.com on May 27, 2019.