5. Testing with Spek

In this chapter we are going to look at unit testing using Spek library. Spek is a behavior-driven development (BDD) style library. The idea behind BDD is that we describe the tests in a slightly less formal style, more spoken like. This makes the tests easy to read and you can pass the tests to non-developers, you can pass them to BAs for example. They can read the test and check that their intent is correct. The library is open source, written in Kotlin and there is a plugin for it in IntelliJ.

How the library works is that we create a class that extends the Spek class, the constructor of whom takes a lambda and that lambda describes the tests.

class CalcSpek : Spek({
//code comes here
})

We write the tests by using a set of keywords, among those keywords are describe and it.

class CalcSpek : Spek({
  describe("the calculator") {
it("should add two numbers") {
assertEquals(26, calculator.add(24,2))
}
}
})

describe – describes the context of the test
it – tells us what this specific test is doing

The idea is that we write test in a very descriptive way, we describe a calculator and it should add two numbers. This comes from the Spek specifications, Spek doesn’t do the assertions. Therefore, when you want to check things are correct, we can use JUnit, AspectJ or others. However, Spek is based on JUnit 5.

Let’s do the tests for a calculator.

Calculator.kt:

class Calculator(val output : Result) {
val total = 0

fun add(a: Int, b: Int) : Int {
return a+b
}

fun accumulate(a : Int) {
total += x
}
}

interface Result {
fun write(answer: Int)
}

class NullResult {
override fun write(answer: Int) {}
}

CalculatorSpek.kt:

class CalculatorSpek : Spek ({
val calculator : Calculator? = null

beforeEach {
calculator = Calculator(NullResult())
}

describe("the calculator") {
it("should add two numbers") {
val result = calculator.add(1, 2)
Assertions.assertEquals(3, result)
}

it("should accumulate one number") {
calculator?.accumulate(10)
Assertions.assertEquals(10, calculator?.total)
}

it("should accumulate two numbers") {
calculator?.accumulate(3)
calculator?.accumulate(4)
Assertions.assertEquals(7, calculator?.total)
}
}
})

Both describe and it take a lambda as their last parameter and when the last parameter in a method is a lambda, instead of adding a parameter in “()”, we can add “{}” block. This is one of the things that make Kotlin really nice when writing things like testing frameworks, they become like a DSL, it looks like it has it’s own language that we have, language that we use for writing tests.

The beforeEach is another Spek keyword, which gets the code inside it executed before every  test runs. Why do we need it in our case? – If we run the test without that code the last assertion will fail because the actual result will 17 – we have accumulated 10 in the second test and 3 and 4 get further accumulated in the 3rd test so the total will be 17. In order to start with “clean” data, we add the beforeEach to create us a new calculator so the total parameter will be 0 at the start of every test.

Mocking in Kotlin is another very well integrated feature. The reason is that the extensions of “Mockito” for Kotlin take advantage of the inferred type inside the language. So we can write code like this:

class CalcSpek : Spek ({
val result : Result = mock()
})

Here for example, we have declared a result val of type Result and we can assign it mock(). We don’t have to tell mock() what to create, it already knows because the val is of type Result. This makes mocking much easier.

 

<< 4. Kotlin and the Java Ecosystem