unit-testing - 函数参数和对象的 Kotlin 单元测试

标签 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))
        }
    }
    

最佳答案

假设 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 是私有(private)的,则不应直接测试其行为,而只能通过其包含类的公共(public)接口(interface)进行测试。

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

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 的交互,一种方法是使用 MyClass1< 中实现的 MyObject 接口(interface)。如果两个类是不同的协作者,从某种意义上说,他们具有独立的、大部分不相关的行为,通常是最好的选择:

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

关于unit-testing - 函数参数和对象的 Kotlin 单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37655431/

相关文章:

python - 一种编写自写测试方法的 Pythonic 方式

java - ArgumentCaptor 并与 hasItems 进行比较

java - 模拟我正在测试的同一个类中的方法调用,它真的是代码味道吗?

kotlin - 二次构造语法 kotlin

android - 更新到 Kotlin 1.3.30 会破坏 Dagger 2.21 的构建

google-app-engine - 如何使用 Kotlin DSL 配置 AppEngine Gradle 插件

java - 如何让 Eclipse 2018.09 默认使用 JUnit 4 测试运行器?

java - 在Java中断言一个集合有一个项目的多个实例?

python - 无法模拟从另一个类继承的类(创建/使用单例对象)

java - 如何在不初始化类的情况下模拟内部成员