Slide 1

Slide 1 text

BBD testing with Spek Simon Vergauwen

Slide 2

Slide 2 text

A Specification Framework

Slide 3

Slide 3 text

What is the goal of BDD? • BDD is also referred to as Specification by Example • Describe the Specification • Ensure the specification by verification • A greater focus on the documentary role of such specifications • Clean and maintained tests • We love clean code so why not love clean test code

Slide 4

Slide 4 text

Table of contents • Structure • Verification and iterative verification • Subject Spek • Technology Compatibility Kits • Mockito kotlin • Extending Spek

Slide 5

Slide 5 text

Structure • 3 types of scopes • Test • it • Action • On • Group • Describe, context and given

Slide 6

Slide 6 text

Structure object FixtureSpec : Spek({ })

Slide 7

Slide 7 text

Structure object FixtureSpec : Spek({
 describe("spek fixtures"){
 }
 })

Slide 8

Slide 8 text

Structure object FixtureSpec : Spek({
 describe("spek fixtures"){
 beforeEachTest { println("hello from outer before each test \n") }
 
 afterEachTest { println("hello from outer after each test \n") }
 }
 })

Slide 9

Slide 9 text

Structure object FixtureSpec : Spek({
 describe("spek fixtures"){
 beforeEachTest { println("hello from outer before each test \n") }
 beforeGroup { println("hello from outer before each group \n") }
 
 afterEachTest { println("hello from outer after each test \n") }
 afterGroup { println("hello from outer after each group \n") }
 }
 })

Slide 10

Slide 10 text

Structure object FixtureSpec : Spek({
 describe("spek fixtures"){
 beforeEachTest { println("hello from outer before each test \n") }
 beforeGroup { println("hello from outer before each group \n") }
 
 context("first nested group") {
 
 }
 
 given("some other nested group") {
 
 }
 
 afterEachTest { println("hello from outer after each test \n") }
 afterGroup { println("hello from outer after each group \n") }
 }
 })

Slide 11

Slide 11 text

Structure object FixtureSpec : Spek({
 describe("spek fixtures"){
 beforeEachTest { println("hello from outer before each test \n") }
 beforeGroup { println("hello from outer before each group \n") }
 
 context("first nested group") {
 it("first test") { println("hello from first context test \n") }
 it("second test") { println("hello from second context test \n") }
 }
 
 given("some other nested group") {
 it("should be 2 as well") { }
 }
 
 afterEachTest { println("hello from outer after each test \n") }
 afterGroup { println("hello from outer after each group \n") }
 }
 })

Slide 12

Slide 12 text

Structure object FixtureSpec : Spek({
 describe("spek fixtures"){
 beforeEachTest { println("hello from outer before each test \n") }
 beforeGroup { println("hello from outer before each group \n") }
 
 context("first nested group") {
 beforeEachTest { println("hello from before each context test \n") }
 it("first test") { println("hello from first context test \n") }
 it("second test") { println("hello from second context test \n") }
 afterEachTest { println("hello from after each context test \n") }
 }
 
 given("some other nested group") {
 beforeEachTest { println("hello from before each given test \n") }
 it("should be 2 as well") { }
 afterEachTest { println("hello from after each given test \n") }
 }
 
 afterEachTest { println("hello from outer after each test \n") }
 afterGroup { println("hello from outer after each group \n") }
 }
 })

Slide 13

Slide 13 text

Structure

Slide 14

Slide 14 text

Verification //every number after the first two is the sum of the two preceding ones fun fibonacci(n: Int): Int {
 tailrec fun loop(n: Int, previous: Int, current: Int): Int =
 if (n == 0) previous else loop(n - 1, current, previous + current)
 
 return loop(n, 0, 1)
 }

Slide 15

Slide 15 text

Verification object FibonacciTest : Spek({
 describe("a fibonacci calculator") {
 
 }
 })

Slide 16

Slide 16 text

Verification object FibonacciTest : Spek({
 describe("a fibonacci calculator") {
 
 //Simple test
 it("Seventh fibonacci number is equal to 13") {
 assertThat(fibonacci(7)).isEqualTo(13)
 } 
 }
 })

Slide 17

Slide 17 text

Verification object FibonacciTest : Spek({
 describe("a fibonacci calculator") {
 
 //Simple test
 it("Seventh fibonacci number is equal to 13") {
 assertThat(fibonacci(7)).isEqualTo(13)
 }
 
 //generation of data
 //Def fibonacci -> sum of previous 2 items = current
 (2..100).forEach { n ->
 
 }
 }
 })

Slide 18

Slide 18 text

Verification object FibonacciTest : Spek({
 describe("a fibonacci calculator") {
 
 //Simple test
 it("Seventh fibonacci number is equal to 13") {
 assertThat(fibonacci(7)).isEqualTo(13)
 }
 
 //generation of data
 //Def fibonacci -> sum of previous 2 items = current
 (2..100).forEach { n ->
 val prev = fibonacci(n - 1)
 val beforePrev = fibonacci(n - 2)
 val cur = fibonacci(n)
 
 }
 }
 })

Slide 19

Slide 19 text

Verification object FibonacciTest : Spek({
 describe("a fibonacci calculator") {
 
 //Simple test
 it("Seventh fibonacci number is equal to 13") {
 assertThat(fibonacci(7)).isEqualTo(13)
 }
 
 //generation of data
 //Def fibonacci -> sum of previous 2 items = current
 (2..100).forEach { n ->
 val prev = fibonacci(n - 1)
 val beforePrev = fibonacci(n - 2)
 val cur = fibonacci(n)
 
 it("$cur should be the sum of the two previous fibonacci numbers: $prev, $beforePrev") {
 assertThat(prev + beforePrev).isEqualTo(cur)
 }
 }
 }
 })

Slide 20

Slide 20 text

Subject Spek open class Calculator {
 fun add(x: Int, y: Int) = x + y
 
 fun subtract(x: Int, y: Int) = x - y
 
 fun divide(x: Int, y: Int) = if (y == 0) throw IllegalArgumentException() else x / y
 }
 
 class AdvancedCalculator : Calculator() {
 fun pow(base: Int, exponent: Int) = Math.pow(base.toDouble(), exponent.toDouble()).toInt()
 }

Slide 21

Slide 21 text

Subject Spek object CalculatorSpec : SubjectSpek({
 subject { Calculator() }
 
 })

Slide 22

Slide 22 text

Subject Spek object CalculatorSpec : SubjectSpek({
 subject { Calculator() }
 
 describe("addition") {
 it("should return the result of adding the first number to the second number") {
 assertThat(subject.add(2, 4)).isEqualTo(6)
 }
 }
 })

Slide 23

Slide 23 text

Subject Spek object CalculatorSpec : SubjectSpek({
 subject { Calculator() }
 
 describe("addition") {
 it("should return the result of adding the first number to the second number") {
 assertThat(subject.add(2, 4)).isEqualTo(6)
 }
 }
 
 describe("subtract") {
 it("should return the result of subtracting the second number from the first number") {
 assertThat(subject.subtract(2, 4)).isEqualTo(-2)
 }
 } 
 })

Slide 24

Slide 24 text

Subject Spek object CalculatorSpec : SubjectSpek({
 subject { Calculator() }
 
 describe("addition") {
 it("should return the result of adding the first number to the second number") {
 assertThat(subject.add(2, 4)).isEqualTo(6)
 }
 }
 
 describe("subtract") {
 it("should return the result of subtracting the second number from the first number") {
 assertThat(subject.subtract(2, 4)).isEqualTo(-2)
 }
 }
 
 describe("division") {
 it("should return the result of dividing the first number by the second number") {
 assertThat(subject.divide(4, 2)).isEqualTo(2)
 }
 
 context("division by zero") {
 it("should throw an exception") {
 assertThatThrownBy({ subject.divide(2, 0) })
 .isInstanceOf(IllegalArgumentException::class.java)
 }
 }
 }
 })

Slide 25

Slide 25 text

Subject Spek object AdvancedCalculatorSpec : SubjectSpek({
 subject { AdvancedCalculator() }
 itBehavesLike(CalculatorSpec)
 
 })

Slide 26

Slide 26 text

Subject Spek object AdvancedCalculatorSpec : SubjectSpek({
 subject { AdvancedCalculator() }
 itBehavesLike(CalculatorSpec)
 
 describe("pow") {
 it("should return the power of base raise to exponent") {
 assertThat(subject.pow(2, 2)).isEqualTo(4)
 }
 }
 })

Slide 27

Slide 27 text

Technology Compatibility Kits Collection List MutableList Set MutableSet

Slide 28

Slide 28 text

Technology Compatibility Kits public interface Collection : Iterable {
 val size: Int
 
 public fun isEmpty(): Boolean
 
 public operator fun contains(element: @UnsafeVariance E): Boolean
 
 override fun iterator(): Iterator
 
 public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
 }

Slide 29

Slide 29 text

Technology Compatibility Kits abstract class CollectionSpek(private val collection: Collection) : Spek({
 
 })

Slide 30

Slide 30 text

Technology Compatibility Kits private val items = arrayOf(1, 2, 3, 4)
 
 abstract class CollectionSpek(private val collection: Collection) : Spek({
 
 describe("requesting the size") {
 it("$collection should have size ${items.size}"){
 assertThat(collection.size).isEqualTo(items.size)
 }
 }
 
 })

Slide 31

Slide 31 text

Technology Compatibility Kits private val items = arrayOf(1, 2, 3, 4) abstract class CollectionSpek(private val collection: Collection) : Spek({
 
 describe("requesting the size") {
 it("$collection should have size ${items.size}"){
 assertThat(collection.size).isEqualTo(items.size)
 }
 }
 
 })
 
 class SetCollectionSpek : CollectionSpek(setOf(*items))
 
 class ListCollectionSpek : CollectionSpek(items.asList())

Slide 32

Slide 32 text

Technology Compatibility Kits interface ComplexClass {
 fun doSomethingComplex(): Boolean
 }

Slide 33

Slide 33 text

Technology Compatibility Kits interface ComplexClass {
 fun doSomethingComplex(): Boolean
 }
 
 class ComplexImpl : ComplexClass {
 override fun doSomethingComplex() = true
 }

Slide 34

Slide 34 text

Technology Compatibility Kits interface ComplexClass {
 fun doSomethingComplex(): Boolean
 }
 
 class ComplexImpl : ComplexClass {
 override fun doSomethingComplex() = true
 }
 
 class SuccesDetermination : ComplexClass {
 override fun doSomethingComplex(): Boolean {
 TODO()
 }
 }
 
 class ComplexImplWithDependency(succesDetermination: SuccesDetermination) :
 ComplexClass by succesDetermination

Slide 35

Slide 35 text

Technology Compatibility Kits abstract class ComplexSpek(private val factory: () -> ComplexClass) : Spek({
 
 val subject = factory.invoke()
 
 describe("A complex class should succeed") {
 assertThat(subject.doSomethingComplex()).isTrue()
 
 }
 
 })

Slide 36

Slide 36 text

Technology Compatibility Kits abstract class ComplexSpek(private val factory: () -> ComplexClass) : Spek({
 
 val subject = factory.invoke()
 
 describe("A complex class should succeed") {
 assertThat(subject.doSomethingComplex()).isTrue()
 
 }
 
 })
 
 object ComplexImplComplexSpek : ComplexSpek({ ComplexImpl() })

Slide 37

Slide 37 text

Technology Compatibility Kits abstract class ComplexSpek(private val factory: () -> ComplexClass) : Spek({
 
 val subject = factory.invoke()
 
 describe("A complex class should succeed") {
 assertThat(subject.doSomethingComplex()).isTrue()
 
 }
 
 })
 
 object ComplexImplComplexSpek : ComplexSpek({ ComplexImpl() })
 
 object ComplexImplWithDependencyComplexSpek : ComplexSpek({
 val succesDetermination = mock {
 on { doSomethingComplex() } doReturn true
 }
 
 ComplexImplWithDependency(succesDetermination)
 })

Slide 38

Slide 38 text

Mockito kotlin testCompile "com.nhaarman:mockito-kotlin:1.3.0"

Slide 39

Slide 39 text

Mockito kotlin class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 val mock = mock()
 
 val mock2 = mock {
 on { getStringValue() } doReturn "stringValue"
 on { someOtherStringValue } doReturn "stringOtherValue"
 }
 
 beforeEachTest { clearInvocations(mock, mock2) }
 
 }
 })

Slide 40

Slide 40 text

Mockito kotlin class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 val mock = mock()
 
 val mock2 = mock {
 on { getStringValue() } doReturn "stringValue"
 on { someOtherStringValue } doReturn "stringOtherValue"
 }
 
 beforeEachTest { clearInvocations(mock, mock2) }
 
 it("calling doSomething") {
 mock.doSomething()
 verify(mock).doSomething()
 }
 
 }
 })

Slide 41

Slide 41 text

Mockito kotlin class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 val mock = mock()
 
 val mock2 = mock {
 on { getStringValue() } doReturn "stringValue"
 on { someOtherStringValue } doReturn "stringOtherValue"
 }
 
 beforeEachTest { clearInvocations(mock, mock2) }
 
 it("assigning a value") {
 mock2.someOtherStringValue = "stringOtherValue2"
 
 verify(mock2).someOtherStringValue = "stringOtherValue2"
 }
 
 }
 })

Slide 42

Slide 42 text

Mockito kotlin class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 val mock = mock()
 
 val mock2 = mock {
 on { getStringValue() } doReturn "stringValue"
 on { someOtherStringValue } doReturn "stringOtherValue"
 }
 
 beforeEachTest { clearInvocations(mock, mock2) }
 
 it("capturing a single value") {
 mock.setSomething(listOf("1", "2"))
 
 verify(mock).setSomething(argThat { size == 2 })
 }
 
 }
 })

Slide 43

Slide 43 text

Mockito kotlin class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 val mock = mock()
 
 val mock2 = mock {
 on { getStringValue() } doReturn "stringValue"
 on { someOtherStringValue } doReturn "stringOtherValue"
 }
 
 beforeEachTest { clearInvocations(mock, mock2) }
 
 it("capturing a single value with multiple assertions") {
 mock.setSomething(listOf("1", "2"))
 
 verify(mock).setSomething(check {
 assertThat(it.size).isEqualTo(2)
 assertThat(it[0]).isEqualTo("1")
 })
 } 
 }
 })

Slide 44

Slide 44 text

Mockito kotlin class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 val mock = mock()
 
 val mock2 = mock {
 on { getStringValue() } doReturn "stringValue"
 on { someOtherStringValue } doReturn "stringOtherValue"
 }
 
 beforeEachTest { clearInvocations(mock, mock2) }
 
 it("capturing multiple value with multiple assertions") {
 mock.setSomething(listOf("1", "2"))
 mock.setSomething(listOf("3", "4"))
 
 argumentCaptor>().apply {
 verify(mock, times(2)).setSomething(capture())
 
 assertThat(allValues.size).isEqualTo(2)
 assertThat(firstValue).isEqualTo(listOf("1", "2"))
 }
 }
 
 }
 })

Slide 45

Slide 45 text

Mockito kotlin class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 val mock = mock()
 
 val mock2 = mock {
 on { getStringValue() } doReturn "stringValue"
 on { someOtherStringValue } doReturn "stringOtherValue"
 }
 
 beforeEachTest { clearInvocations(mock, mock2) }
 
 it("testing order of execution") {
 mock.getStringValue()
 mock2.getStringValue()
 
 inOrder(mock, mock2) {
 verify(mock).getStringValue()
 verify(mock2).getStringValue()
 }
 }
 }
 })

Slide 46

Slide 46 text

Mockito kotlin class MyOtherClass(val number: Int) {
 
 init {
 if(number <= 1) error("$number should be greater than 1")
 }
 }

Slide 47

Slide 47 text

Mockito kotlin class MyOtherClass(val number: Int) {
 
 init {
 if(number <= 1) error("$number should be greater than 1")
 }
 } class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 MockitoKotlin.registerInstanceCreator { MyOtherClass(2) } 
 }
 })

Slide 48

Slide 48 text

Mockito kotlin class MyOtherClass(val number: Int) {
 
 init {
 if(number <= 1) error("$number should be greater than 1")
 }
 } class MockitoExample : Spek({
 
 describe("mockito-kotlin") {
 
 MockitoKotlin.registerInstanceCreator { MyOtherClass(2) }
 
 val mock3 = mock()
 
 it("verify that mocked correctly") {
 assertThat(mock3.number).isEqualTo(2) //FAILS!!!
 }
 }
 })

Slide 49

Slide 49 text

Extending Spek infix fun Pair.to(that: C) =
 Triple(this.first, this.second, that)
 
 fun TestContainer.tableOf(vararg elements: T, f: (TestContainer.(elements: T) -> Unit)) =
 elements.toList().forEach { f.invoke(this, it) }
 
 class TableSpekTest : Spek({
 
 })

Slide 50

Slide 50 text

Extending Spek infix fun Pair.to(that: C) =
 Triple(this.first, this.second, that)
 
 fun TestContainer.tableOf(vararg elements: T, f: (TestContainer.(elements: T) -> Unit)) =
 elements.toList().forEach { f.invoke(this, it) }
 
 class TableSpekTest : Spek({
 describe("zipping lists") {
 tableOf(
 listOf(1, 2, 3) to listOf(4, 5, 6) to listOf(5, 7, 9),
 listOf(1, 2, 3) to listOf(1, 2, 3) to listOf(2, 4, 6),
 listOf(4, 5, 6) to listOf(1, 2, 3) to listOf(5, 7, 9)
 ) { (l1, l2, result) ->
 }
 }
 })

Slide 51

Slide 51 text

Extending Spek infix fun Pair.to(that: C) =
 Triple(this.first, this.second, that)
 
 fun TestContainer.tableOf(vararg elements: T, f: (TestContainer.(elements: T) -> Unit)) =
 elements.toList().forEach { f.invoke(this, it) }
 
 class TableSpekTest : Spek({
 describe("zipping lists") {
 tableOf(
 listOf(1, 2, 3) to listOf(4, 5, 6) to listOf(5, 7, 9),
 listOf(1, 2, 3) to listOf(1, 2, 3) to listOf(2, 4, 6),
 listOf(4, 5, 6) to listOf(1, 2, 3) to listOf(5, 7, 9)
 ) { (l1, l2, result) ->
 
 it("zipping $l1 and $l2 should result in $result") {
 assertThat(l1.zip(l2, { i1, i2 -> i1 + i2 })).isEqualTo(result)
 }
 }
 }
 })

Slide 52

Slide 52 text

BBD testing with Spek Questions? Simon Vergauwen