【问题标题】:Test lambda functions in Android with Kotlin使用 Kotlin 在 Android 中测试 lambda 函数
【发布时间】:2018-05-09 15:14:40
【问题描述】:

我需要对函数doClassAction 进行单元测试,并在其中调用对象store 上的函数doStoreAction。 这个doStoreAction 接受两个参数,一个整数和一个函数,如下例所示

class MyStore() {

    fun doStoreAction(num: Int, callback: (text: String) -> Unit) {
        // It does something 
        // ...
        // and when it's done it calls the callback

        return callback("some text")
    }
}

class MyClass(private val store: MyStore,
              private val objectX: MyObject) {

    fun doClassAction(num: Int) {
        store.doStoreAction(num) { callbackResult ->
            // Action (potentially asynchronous)
            // that will happen after obtaining the value via the callback

            objectX.doObjectAction(callbackResult)
        }
    }
}

我正在使用Mockito,到目前为止我的测试有以下几行

@Test
fun doClassActionTest() {
    val mockStore = mock(MyStore::class.java)
    val mockObject = mock(MyObject::class.java)
    val class = MyClass(mockStore, mockObject)
    class.doClassAction(42)
}

但它没有编译,因为对方法的调用没有指定回调...我不想覆盖它,因为我希望测试使用原始的并验证里面的东西被正确调用,比如:

when(objectX.doObjectAction(anyString())).doNothing()
verify(objectX, times(1)).doObjectAction(callbackResult)

有没有办法调用该方法并模拟我在测试中设置的值的回调响应,但仍然让它通过原始代码流?

【问题讨论】:

    标签: android unit-testing lambda kotlin mockito


    【解决方案1】:

    经过几天的尝试和阅读,我终于找到了一个可行的解决方案,我将在这里分享给任何发现自己在同一个泡菜中的人

    @Test
    fun doClassActionTest() {
        val mockStore = mock(MyStore::class.java)
        val mockObject = mock(MyObject::class.java)
        val myClass = MyClass(mockStore, mockObject)
        val input = 42
        val resultCallback = "test result"
    
        `when`(mockStore.doStoreAction(any(), any())).then { invocation ->
            (invocation.arguments[1] as (String) -> Unit).invoke(resultCallback)
        }
    
        myClass.doClassAction(input)
    
        verify(mockObject, only()).doObjectAction(resultCallback)
    }
    

    这里需要注意的是,请记住将您正在模拟的类以及这些类调用的方法作为 open 在 Kotlin 中,否则可能会出现误报

    附:我还使用了一些从mockito-kotlin 库中提取的内联函数,例如:

    inline fun <reified T : Any> any() = Mockito.any(T::class.java) ?: createInstance<T>()
    
    inline fun <reified T : Any> createInstance(): T = createInstance(T::class)
    
    fun <T : Any> createInstance(kClass: KClass<T>): T = castNull()
    
    @Suppress("UNCHECKED_CAST")
    private fun <T> castNull(): T = null as T
    

    【讨论】:

    • 要处理要打开的类的情况以便能够测试它们,您可以使用 Kotlin allopen 插件。在这里查看kotlinlang.org/docs/reference/compiler-plugins.html。
    • 你可以使用来自同一个库的whenever()扩展而不是丑陋的`when`。
    • 在找到您的答案之前一直在使用这种方法:dev.to/ychescale9/…。感谢您提供这种方法!
    猜你喜欢
    • 2019-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多