@hhariri hhariri released this Mar 26, 2017

Assets 2

What's new?

Extensions

We've added support for Extensions in Spek, allowing you to extend Spek with specific functionality. The extensibility model relies on Kotlin language features. This is an experimental feature and is subject to change in future releases. We do need your feedback though!

See #115 for more details.

Data Driven

Data Driven testing is back to Spek and this time better than before! You can now run the same tests on multiple input values:

class DataDrivenSpec : Spek({

    given("a calculator") {

        val calculator = Calculator()

        val data = arrayOf(
                data(4, 2, expected = 6),
                data(1, 3, expected = 4),
                data(5, 7, expected = 12)
        )

        on("addition %s and %s", with = *data) { input1, input2, expected ->

            it("returns $expected") {
                assertEquals(expected, calculator.add(input1, input2))
            }
        }

        on("%s subtract %s and subtract %s",
                data(10, 5, 3, expected = 2),
                data(100, 50, 8, expected = 42),
                data(0, 5, 3, expected = -8)
        ) { minuend, subtrahend1, subtrahend2, expected ->

            it("returns $expected") {
                assertEquals(calculator.subtract(calculator.subtract(minuend, subtrahend1), subtrahend2), expected)
            }
        }

        on("%s divided by %s", with = data(10, 2, expected = 5)) { dividend, divisor, result ->

            it("returns $result") {
                assertEquals(calculator.divide(dividend, divisor), result)
            }
        }
    }
})

Thanks to @artem-zinnatullin , @igor-korotenko and @FaustXVI for their contributions for this.

Action Scopes

A special type of group scope which is only evaluated during the execution phase. It can contain any number of test scopes but not group scopes or fixtures. Typically you use this if you want to assert the result or side effect of a specific "action".

action("some action") {
    val result = service.doSomething()

    it("should be eq to some value") { assertEquals(XXX, result) }
}

This was also possible with 1.0 however it was a bit more involved:

describe("some action") {
    var result: Result? = null
    beforeGroup { result = service.doSomething() }
    it("should be eq to some value") { ... }
}

Object instances

It's now possible to use object instances when writing specs.

object MySpec: Spek({
    ...
})

Spek inclusion

Allows you to include on Spek inside another. Works well with object instances.

object MySpec: Spek({ ... })

object AnotherSpec: Spek({
    include(MySpec)
    ...
})

Memoization

You can bind values to Spek's lifecycle and have them memorised. By specifying the caching using CachingMode, we can define how it relates to the lifecycle. By default caching mode is set to CachingMode.TEST.

object MySpec: Spek({
      val foo by memoized(mode) { SomeService() }
      test("do something") { foo.bar() }
})

Below are the possible values for mode.

  • TEST - each test will have a unique instance.
  • GROUP - each group will have a unique instance.
  • SCOPE - there will be only one instance within the scope it was declared.

The example above uses Kotlin 1.1, however it's possible to use it with earlier versions of Kotlin too:

object MySpec: Spek({
      val foo = memoized { SomeService() }
      test("do something") { foo().bar() }
})

Breaking Changes

Fixtures

  • renamed beforeEach and afterEach to beforeEachTest and afterEachTest, respectively.

The behaviour for beforeEach and afterEach has changed. These now are run for each test, allowing for scenarios where for instance test context needs to be reset. This might impact the behaviour of tests and as such, to make the change more obvious, we've also renamed the functions, which now are more aligned with their actual behaviour.

Subject

Some changes with subject, namely:

  • subject has been reimplemented as an extension and moved into its own artifact (org.jetbrains.spek:spek-subject-extension), effectively making it an opt-in feature.
  • When using shared subjects it is now mandatory to use object instances.
    itBehavesLike(SharedSubject) // itBehavesLike(SharedSubject::class)

Other changes

  • (#145) Added beforeGroup and afterGroup fixtures
  • (#176) Handle exceptions gracefully during discovery phase.
  • (#178) Ensure fixtures are always executed last.
  • (#172) Allow local delegation for LifecycleAware objects.
  • (#166) Ignore abstract classes.
  • (#171) Make InstanceFactory more lenient.
  • (#154) Don't allow fixtures inside action scopes.