在Kotlin中,我们可以有函数对象并作为函数参数传入。
funcParam
)如何对具有功能参数的功能进行单元测试? (例如下面的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))
}
}
答案 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"))
}
}
如果您想测试MyClass1
与MyObject
的互动方式,则可以使用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
}
}
如果MyClass1
和MyObject
互动更复杂(即涉及更多呼叫queries and commands),则意味着他们是密切合作的同事。在这种情况下,使用模拟会导致脆弱且难以编写测试。