首页 > 解决方案 > 如何模拟 Kotlin 的 List.forEach?

问题描述

对于下面给定的代码,在 Kotlin 中,无法执行该函数forEach(或任何类似的,map, filter,等等...),因为BarList 它是模拟的。forEach所以没有调用和亲属的本机实现。在互联网上进行了一些搜索后,我得到了这个:

public class BarList<E> extends AbstractList<E> implements OrderedBarCollection<E> { 
    //...
}
//...

val mockedList: BarList<Foo> = mockBarList()
val fooList = listOf(Foo())

`when`(mockedList.iterator()).thenReturn(fooList.iterator())
`when`(mockedList.size).thenReturn(fooList.size)

com.nhaarman.mockito_kotlin
    .doCallRealMethod()
    .`when`(mockedList)
    .forEach(Mockito.any<Consumer<Foo>>()) //Attempt to call the Consumer.

mockedList.forEach { foo ->
    //Not executing
}

我根据这个问题的答案在上面尝试了这个:https ://stackoverflow.com/a/49407513/2430555

我也试过:

com.nhaarman.mockito_kotlin.doCallRealMethod().`when`(mockedList).forEach(any())

但它导致:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
//...

forEachKotlin 源码中的定义是:

public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit

我想我应该用any()匹配的东西替换action: (T) -> Unit,但我不知道该怎么做。如果需要,我不介意使用交互器,但我至少需要forEach按预期运行。你们能帮帮我吗?

问候,

佩德罗

标签: kotlinmockitopowermockrobolectricmockito-kotlin

解决方案


解决方案是使用thenAnswer而不是模拟thenReturn列表。

`when`(mockedList.iterator()).thenAnswer { fooList.iterator() }

原因:

作者:托拜厄斯·伯杰

迭代器只适用于遍历列表一次。因此,每次调用 iterator() 函数时通常都会得到一个新的。如果你用 thenReturn(messageList.iterator()) 模拟它,它只会在 messageList 上调用一次,并在你每次尝试为你的模拟获取一个迭代器实例时重用该迭代器实例。一旦你对这个迭代器的第一个循环完成,它总是会说它没有更多的项目。使用 thenAnswer 您定义了一个供应商,每次使用您的模拟函数时都会调用它,为每次调用提供一个新的迭代器(正如预期的那样)


推荐阅读