首页 文章

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

提问于
浏览
1

在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))
    }
}

1 回答

  • 3

    假设有意 funcParampublic ,您可以像任何其他方法一样测试它:

    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 是私有的,你不应该't test its behavior directly but only through public interface of it'含有类 .

    测试 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"))
        }
    }
    

    如果你想用 MyObject 测试 MyClass1 交互,一种方法是使用 MyClass1 中的接口实现 MyObject . 通常最好的选择是,如果两个类是不同的协作者,在某种意义上它们具有大多不相关的行为:

    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),则意味着他们是密切合作的同伴 . 在这种情况下,使用模拟会导致脆弱且难以编写测试 .

相关问题