【问题标题】:Mocked suspend function returns null in Mockito模拟挂起函数在 Mockito 中返回 null
【发布时间】:2019-04-05 12:59:40
【问题描述】:

我有一个使用 Mockito 模拟的挂起函数,但它返回 null

两个项目都使用

'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0'

示例 1

这是我的测试,其中模拟返回 null

@Test
fun `when gps not enabled observer is notified`() = runBlocking {
    // arrange
    `when`(suspendingLocationService.getCurrentLocation()).thenReturn(result) // <- when called this returns null

    // act
    presenter.onStartShopButtonClick()

    // assert
    verify(view).observer
    verify(observer).onPrepareShop()
}

我的演示者中有以下实现

  override suspend fun onStartShopButtonClick() {
    val result = suspendingLocationService.getCurrentLocation() // <- in my test result is null!!!!!!
    view?.apply {
        observer?.onPrepareShop()
        when {
            result.hasGivenPermission == false -> observer?.onStartShop(StoreData(), APIError(APIError.ErrorType.NO_PERMISSION))
            result.hasGPSEnabled == false -> observer?.onStartShop(StoreData(), APIError(APIError.ErrorType.GPS_NOT_ENABLED))
            result.latitude != null && result.longitude != null ->
                storeLocationService.getCurrentStore(result.latitude, result.longitude) { store, error ->
                    observer?.onStartShop(store, error)
                }
        }
    }
}

但是我相信下面正在运行的非常相似的实现

示例 2

下面的测试确实通过了,正确的函数确实响应了一个产品

@Test
fun `suspending implementation updates label`() = runBlocking {
    // arrange
    `when`(suspendingProductProvider.getProduct("testString")).thenReturn(product)

    // act
    presenter.textChanged("testString")

    // assert
    verify(view).update(product.name)
}

这里是presenter的实现

override suspend fun textChanged(newText: String?) {
    val product = suspendingNetworkProvider.getProduct(newText)
    view?.update(product.name)
}

这是我正在模拟的界面

interface SuspendingProductProvider {
    suspend fun getProduct(search: String?): Product
}

在第一个示例中我没有做的事情

【问题讨论】:

    标签: junit kotlin mockito kotlinx.coroutines


    【解决方案1】:

    Mockito 对 suspend 函数有特殊支持,但在 Kotlin 1.3 中,协程内部实现方式发生了一些变化,因此旧版本的 Mockito 不再识别由 Kotlin 1.3 编译的 suspend 方法。而kotlinx.coroutines 从 1.0.0 版开始使用 Kotlin 1.3。

    相应的支持已添加到 Mockito,但仅限于 since version 2.23,因此更新您的 Mockito 版本会有所帮助。

    【讨论】:

    • 我正在使用 org.mockito:mockito-core:3.3.0,但我仍然有这个问题
    • Mockito 3.3.3,同样的问题。 @iori24 你找到解决方法了吗?
    【解决方案2】:

    首先获取Mockito-kotlin 和 在 mockito 中,当你想模拟 suspend functions 时可以使用此代码:

            val mockedObject: TestClass = mock()
            mockedObject.stub {
                onBlocking { suspendFunction() }.doReturn(true)
            }
    

    【讨论】:

      【解决方案3】:

      最佳答案是正确答案。我升级到 mockito 2.23 并且能够成功地做到这一点,而没有遇到 null 值的问题。我在 mockito 2.21 上遇到了同样的问题

      class Parser {
      suspend fun parse(responseBody: ByteArray) : Result = coroutineScope {/*etc*/}
      }
      
      val expectedResult = Mockito.mock(Result::class.java)
      Mockito.`when`(mockParser.parse(byteArrayOf(0,1,2,3,4))).thenReturn(coroutineScope {
       expectedResult
      })
      

      【讨论】:

        猜你喜欢
        • 2020-03-13
        • 1970-01-01
        • 1970-01-01
        • 2020-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-08
        • 1970-01-01
        相关资源
        最近更新 更多