Your team of exceptional Java software engineers

Your team of exceptional Java software engineers

The first 98 elements exist in nature, although some are found only in trace amounts and others were synthesized in laboratories before being found in nature.

We build fast, reliable fintech back-ends

Kotlin + Gradle + Spek 2 + JUnit 5 - a simple guide

Tomek Wałkuski, 


I wanted to try out Kotlin + Spek 2 testing framework combination. It turns out both Gradle and Spek 2 documentation leave much to be desired... So here it is a step-by-step guide to build a simple application.

A calculator that allows to add and divide numbers is enough demonstrate all required Gradle configuration options and introduce Spek 2 specs syntax. Let's start with the desired test structure. Framework is inspired heavily by RSpec so Ruby developers will feel at home and find familiar keywords, like describe, context, and it blocks:

// file: src/test/kotlin/com/_98elements/CalculatorSpec.kt

package com._98elements

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.assertThrows
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe

object CalculatorSpec: Spek({
    describe("adding numbers") {
        it("adds 2 to 2") {
            assertEquals(4, Calculator.add(2, 2))
        }
    }

    describe("dividing numbers") {
        it("divides 4 by 2") {
            assertEquals(2, Calculator.divide(4, 2))
        }

        context("when dividing by 0") {
            it("throws ArithmeticException") {
                assertThrows<ArithmeticException> { Calculator.divide(2, 0) }
            }
        }
    }
})

It is easy to implement the code to make the specs pass:

// file: src/main/kotlin/com/_98elements/Calculator.kt

package com._98elements

object Calculator {
    fun add(a: Int, b: Int) = a + b

    fun divide(a: Int, b: Int) = a / b
}

How to run the specs? gradle init command will create a basic project structure for us. We will need to provide the configuration options in the settings.gradle and build.gradle files:

// settings.gradle

rootProject.name = 'calculator'
// build.gradle

buildscript {
    // use specific Kotlin version
    ext.kotlin_version = '1.2.61'
}

plugins {
    // install Kotlin JVM gradle plugin
    id 'org.jetbrains.kotlin.jvm' version '1.2.61'
}

repositories {
    mavenCentral()
    
    // add Spek 2 development repository
    maven { url "https://dl.bintray.com/spekframework/spek-dev" }
}

dependencies {
    // include Kotlin standard library
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

    // include JUnit 5 assertions
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.2.0'
    
    // include Spek 2 library
    testImplementation 'org.spekframework.spek2:spek-dsl-jvm:2.0.0-alpha.1'

    // include JUnit 5 test engine
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.2.0'
    
    // include Spek 2 JUnit test engine
    testRuntimeOnly 'org.spekframework.spek2:spek-runner-junit5:2.0.0-alpha.1'
}

// configure test task to use Spek 2 test engine with JUnit
test {
    useJUnitPlatform {
        includeEngines 'spek2'
    }
}

// set JVM target to 1.8 for all compilation tasks
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

JUnit 5 dependency is required as Spek 2 doesn't provide any assertions library. See JUnit 5 User Guide for a detailed documentation. Alternatives include kotlin-test, HamKrest, Expekt, and Kluent.

Now we are finally able to run the tests with the help of generated Gradle wrapper:

$ ./gradlew test

BUILD SUCCESSFUL in 2s
3 actionable tasks: 2 executed, 1 up-to-date

And what if we break one test? Let's find out:

$ ./gradlew test

> Task :test FAILED

com._98elements.CalculatorSpec > adds 2 to 2 FAILED
    org.opentest4j.AssertionFailedError at CalculatorSpec.kt:11

3 tests completed, 1 failed

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///Users/tomek/depot/personal/calculator/build/reports/tests/test/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s
3 actionable tasks: 2 executed, 1 up-to-date

I hope this blog post will guide you through the setup of Spek 2 framework with Kotlin and Gradle in no time!

You can find the code for this blog post at 98elements/calculator GitHub repository.