Leveraging Kotlin for Tests

Given/When/Then

You may have heard of the Given/When/Then pattern — also known as the Cucumber/Gherkin syntax — if you have written tests before, or you might even recognize it from Jira tickets.
Originally introduced as a part of BDD (Behavior Driven Development), similar patterns like the Four-Phase Test (you’ll see some similarities to JUnit here) have existed for a good amount of time. Martin Fowler gives a good small summary of all of this in his article about the Given/When/Then pattern:

I heard that adding a featured image helps increase clicks. Does it work? Who knows! If it does, thank you, Sigmund on Unsplash!

Test Names

I argue that test names are one of the most important parts of writing good tests. The name of the test should help you understand what the test does.
One quality of a good test is that it fails when the actual outcome is different from the expected outcome. When a test fails, it should be easy to understand why it failed. Think of a test failing on CI; it’s great if you can get a good understanding and maybe a first hunch from the test name already). You might know tests similar to this:

Structuring Test Code

The Given/When/Then pattern can be applied in different ways, and all of them work well for different use cases. One of the approaches suggested by Martin Fowler is using comments to mark the regions of the test:

Providing a formal structure using a DSL

Test frameworks such as Spek help enforce a more formal structure using Kotlin DSLs. Take this test written with Spek’s Gherkin-inspired syntax:

https://www.spekframework.org/gherkin/

Expressing the “Given” scenario as a class

Regardless of whether you are following the Given/When/Then pattern or not, it is worth considering expressing the requirements of a test in a class. Say you need to provide a mock or a fake for your subject under test:

More backtick functions… for Given scenarios!

Lastly, we can introduce some sugar on top of the Given class to make expressing scenarios more fluent. We can make our Given class a data class to benefit from the copy function and use extension properties to define scenarios:

“Given“ Builders

Another approach to the Given is creating a builder for the Given model. This works especially well when you are using a DSL but is useful for any scenario with complex inputs. Higher-order functions with a receiver can help create a nice DSL:

Footnotes

¹ There is a caveat to this language feature though: it’s not available on Android platforms before SDK 30, so if you are writing instrumented tests and are not ready to go to minSdk 30 for your tests (understandably), you won’t be able to use this feature. Backtick function names work on JVM targets though, so these make sense especially for unit tests. But some other patterns can be used to improve your test code!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jossi Wolf

Jossi Wolf

864 Followers

Software Engineer @Google working on Jetpack Compose. I like Kotlin, Animations and Rabbits! speakerdeck.com/jossiwolf