我应该如何在 Spek 中设置可变测试装置?

How should I set up mutable test fixtures in Spek?

我正在努力了解 Spek 中的固定装置。 The Calculator example in the docs 很容易理解,但我不确定如何在某些固定装置是有状态的情况下构建 setup/teardown。例如,如果我正在测试一个列表:

describe("a list") {
    val list = arrayListOf<Int>() // Only instantiated once

    on("adding an item") {
        list.add(123)

        it("has a size of one") {
            list.size.should.equal(1)
        }
    }

    on("adding 2 items") {
        list.add(1)
        list.add(2)

        it("has a size of 2") {
            list.size.should.equal(2) // Fails, 3 != 2
        }
    }
}

据我了解,在 Spek 中,describe 块仅被评估一次,因此只有一个 List 实例。文档很有帮助地建议使用测试装置,但是 毫无帮助 没有给出示例!

我假设以下内容不起作用,因为 Kotlin 不明白 Spek 肯定会在 on

之前调用 beforeEachTest
describe("a list") {
    var list : MutableList<Int>

    beforeEachTest {
        list = arrayListOf()
    }

    on("adding an item") {
        list.add(123) // Compile error, list must be initialised

我可以通过使变量可为空来解决这个问题,但是我必须在任何地方都使用 nullsafe 运算符,这很糟糕,因为我知道它永远不会为 null:

describe("a list") {
    var list : MutableList<Int>? = null

    beforeEachTest {
        list = arrayListOf()
    }

    on("adding an item") {
        list?.add(123) // Bleh

这也有效,但这意味着现在需要在两个地方复制每一位设置代码

describe("a list") {
    var list = arrayListOf<Int>()

    beforeEachTest {
        list = arrayListOf() // Bleh
    }

    on("adding an item") {
        list.add(123)

对不起,如果其中任何一个是显而易见的,但我来自 JUnit 世界,在这个世界中,绝对所有东西(静态条)在每次测试之前都被拆除并重建,所以这一切看起来都很陌生!

如果您使用 Kotlin 1.1 和 Spek 1.1.0,您可以使用 memoized.

describe("a list") {
    val list by memoized { arrayListOf<Int>() }

    on("adding an item") {
        list.add(123)

        it("has a size of one") {
            list.size.should.equal(1)
        }
    }

    on("adding 2 items") {
        list.add(1)
        list.add(2)

        it("has a size of 2") {
            list.size.should.equal(2)
        }
    }
}

每个 on 都会有一个 list 的唯一实例。您可以将 CachingMode 传递给 memoized 以控制 Spek 缓存值的方式。

  • CachingMode.TEST(默认)- 每个测试都会有一个唯一的实例(on 这里是一个特例,被视为 test
  • CachingMode.SCOPE - 将有一个独特的实例,实际上是一个单例。
  • CachingMode.GROUP - 每个 group 都会有一个独特的实例。

memoized 在 Kotlin 1.1 和至少 Spek 1.1.0-beta3 之前仍然可用,但语法有点笨拙。

describe("a list") {
    val list = memoized { arrayListOf<Int>() }

    on("adding an item") {
        list().add(123)

        it("has a size of one") {
            list().size.should.equal(1)
        }
    }

    on("adding 2 items") {
        list().add(1)
        list().add(2)

        it("has a size of 2") {
            list().size.should.equal(2)
        }
    }
}