功能参数和对象的Kotlin单元测试

时间:2016-06-06 10:46:53

标签: unit-testing mockito kotlin

在Kotlin中,我们可以有函数对象并作为函数参数传入。

  1. 如何创建单元测试来测试功能对象逻辑? (例如,下面的funcParam
  2. 如何对具有功能参数的功能进行单元测试? (例如下面的functionWithFuncParam) - 即我可以为funcParam创建模拟吗?

    class MyClass1(val myObject: MyObject) {
        val funcParam = fun (num: Int): Int {
            return num * num
        }
    
        fun myFunctionOne() {
            myObject.functionWithFuncParam(funcParam)
        }
    }
    
    class MyObject () {
        fun functionWithFuncParam(funcParam: (Int) -> Int) {
            println(funcParam(32))
        }
    }
    

1 个答案:

答案 0 :(得分:3)

假设funcParam有意public,您可以像其他任何方法一样对其进行测试:

class MyClass1Tests {
    val sut = MyClass1(MyObject())

    @Test
    fun `funcParam multiplies input`() {
        assertThat(sut.funcParam(4), equalTo(16))
        assertThat(sut.funcParam(1), equalTo(1))
        assertThat(sut.funcParam(0), equalTo(0))
        assertThat(sut.funcParam(-10), equalTo(100))
    }
}

如果funcParam是私有的,您不应该直接测试其行为,而只能通过其包含类的公共接口来测试。

在测试functionWithFuncParam时,您可以轻松提供(Int) -> Int的存根实现:

class MyObjectTests {
    val outContent = ByteArrayOutputStream().apply {
        System.setOut(PrintStream(this))
    }
    val sut = MyObject()
    @Test
    fun `functionWithFuncParam prints function output `() {
        sut.functionWithFuncParam { 12345678  }
        assertThat(outContent.toString(), containsString("12345678"))
    }
}

如果您想测试MyClass1MyObject的互动方式,则可以使用MyObject中的接口实施MyClass1。如果两个类是不同的合作者,通常是最佳选择,因为它们具有大多不相关的行为:

interface FunctionalObj {
    fun functionWithFuncParam(funcParam: (Int) -> Int)
}
class MyClass1(val myObject: FunctionalObj) {
//omitted for brevity
}
class MyClass1Tests {
    var params = mutableListOf<(Int)->Int>()
    val sut = MyClass1(object: FunctionalObj {
        override fun functionWithFuncParam(funcParam: (Int) -> Int) { params.add(funcParam) }
    })

    @Test
    fun `myFunctionOne calls delegate`() {
        sut.myFunctionOne()
        assertThat(params.size, equalTo(1))
        assertThat(params[0], equalTo(sut.funcParam))//only if `funcParam` is public
    }
}

如果MyClass1MyObject互动更复杂(即涉及更多呼叫queries and commands),则意味着他们是密切合作的同事。在这种情况下,使用模拟会导致脆弱且难以编写测试。