Bacon Driven Development in Kotlin with Spek

A readable version of my talk at Droidcon Bangkok

Travis P
Black Lens
Published in
6 min readApr 14, 2017

--

You heard people say unit tests should make up to 70% of all your tests, right? Yeah, me too, I’ve heard so much about how important unit test is and I felt bad I didn’t know how to do any kind of automated test at the time.

There are many videos and blog posts on how to do a unit test out there, but in terms of testing in Android development, there were not enough back then. I remember I’ve read how to test a calculator for 5 times from 5 different authors and still had no idea how to test my Android code. Until one day, I found the Android Testing Codelab which taught me exactly how to test my Android code.

The most important thing I learned from the codelab is you can’t just go old school and write everything in the Activity then expect it to be testable. You need to write and structure your code in a testable manner. This is where Model-View-Presenter pattern or MVP (not to be confused with Minimum Viable Product) comes in. It allows you to write a testable code. You can dig a little deeper on MVP in one of my earlier blog post.

I’m not an expert on this but in this blog post, I will try to write a unit test in Kotlin using Spek framework. I’ll use the Notes application from the codelab as an example.

Why Kotlin?

I am a huge fan of Kotlin. Kotlin is a statically typed JVM language with 100% Java interoperability — which means you can gradually integrate Kotlin into your Java/Android project. It supports both object oriented and functional programming. It is concise and easy to pick up. Once you get a grasp on it, you’ll never want to write your code in Java ever again.

The Android Testing Codelab is the best tutorial I’ve seen so far. The unit test is written in Java using JUnit 4 framework.

Spek?

Your typical JUnit tests would look like this.

It is somewhat readable but it’s definitely not pretty. You have to name your test method in a semi-English fashion.

Spek can help you with that. Spek allows you to write your unit tests in human readable sentences as if you are describing a specification for your code — hence the name Spek.

You will write Spek code in Kotlin but the class under test can be in Java or Kotlin.

Wait, what does this has anything to do with bacon? 🥓

While I was reading through the Spek website, I found this in the FAQ section.

http://spekframework.org/docs/latest/#_faq

This is one of the reasons why I love being a developer. We are allowed to have fun doing our job. There are jokes, puns, humors and creativity everywhere in the industry. Being an ex-chemical engineer myself, I didn’t find people call a valve “Espresso”, call a reactor “Volley” or name a chemical process after a CBS fictional character “Mosby”.

Setup

Add Kotlin to your project

Just follow the instruction from the official website. It’s super easy. Install Kotlin plugin in Android Studio then invoke Tools | Kotlin | Configure Kotlin in Project action. The plugin will add things in your build.gradle files.

Add Spek to your project

It’s a little tricky setting up in Android Studio. The instructions in the Spek official documentation didn’t quite work but reading through Slack Archive helps.

Install Spek plugin, then add Spek dependencies to your module level build.gradle.

dependencies {
// ...
testCompile "org.jetbrains.spek:spek-api:1.1.0-beta3"
testCompile "org.jetbrains.spek:spek-junit-platform-engine:1.1.0-beta3"
testCompile "org.junit.platform:junit-platform-runner:1.0.0-M3"
}

repositories {
// ...
maven { url "http://dl.bintray.com/jetbrains/spek" }
}

Sync your project with gradle files and it will complain your app’s Kotlin version and test’s are not the same. You can either exclude one by one.

testCompile("org.jetbrains.spek:spek-api:1.1.0-beta3", {
exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
})

Or you can force the resolution strategy once and for all.

configurations.all {
resolutionStrategy.force "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

Then add assembleMockDebugUnitTest (or your flavor of choice) to your default Spek run config.

The doc said you have to annotate your spec classes with @RunWith(JUnitPlatform::class). Doing so will cause some confusion to the Spek plugin, it won’t recognize your spec and create a JUnit config to run your spec instead — which doesn’t work (in Android Studio 2.3, Spek plugin 0.3.3). But we can fix this. You can remove the @RunWith annotation completely, it works just fine (so far). Or you can create a Spek run config yourself.

Run config for a single spec
Run config for all specs in a package

Mockito-Kotlin

Mockito-Kotlin lets us write Mockito statement Kotlin-style.

dependencies {
testCompile "com.nhaarman:mockito-kotlin:1.3.0"
}

Notes — a simple note taking app

Taken shamelessly from the codelab

The app under test is a simple note taking app. It consists of 4 screens. Notes, Add Note, Note Detail and Statistics. The statistics screen is not yet implemented so you can totally ignore it.

The app is built with MVP pattern. You do know you can’t write everything in an Activity and expect it to be testable, right? You need some kind of structure to make it testable. In MVP each screen has its own View and UserActionsListener(Presenter) interfaces defined. The shared NoteRepository acts as a Model for every screen.

I’ll be converting JUnit tests to Specs.

Now I’m gonna ask you to read section 1 to 6 in the codelab, if you haven’t already.

NotesPresenterSpec

You create a test class (or a test object — singleton in Kotlin) extended from Spek passing in a lambda (function/block of code) as a constructor parameter.

Spek uses DSL to enable us to write test in human language. given accepts a String description and a lambda as arguments and creates a group scope. You can have nested groups in case you need to group your test for some reasons.

In a group, you do the setup. You mock dependencies with mockito-kotlin’s global function mock() without specifying a type (the power of reified generics) then create our subject — notesPresenter.

callbackCaptor = argumentCaptor<NotesRepository.LoadNotesCallback>() is what you do when your test involve callback, this is mockito stuff, you can look it up.

afterTest{} is obvious enough, after a test you reset your mock.

on also accepts a description String and a lambda. on creates an action scope. This where you describe what are you going to test and actually do it.

it also accepts a description String and a lambda. it creates a test scope. This is where you describe what you expect form a test and actually assert it.

You hit run, it compiles, it runs and it passes.

Conclusion

So that’s Spek, it allows you to write human-readable-understandable tests — essentially a specification for your class. All you have to do is learn Kotlin (super shallow learning curve) and read a really short Spek documentation.

P.S. This is a draft for my talk at Droidcon Bangkok but I didn’t have the time to finish it until now. Sorry for the delay. I hope you get the rough idea, study further and if you find it useful — use it and spread the word.

--

--

Travis P
Black Lens

Android Developer, Kotlin & Flutter Enthusiast and Gamer