如何模拟 Kotlin 的 List.forEach?
How to mock Kotlin's 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
}
我在上面根据这个问题的答案试过了:
我也试过:
com.nhaarman.mockito_kotlin.doCallRealMethod().`when`(mockedList).forEach(any())
但它导致:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
//...
Kotlin源码中forEach
的定义是:
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit
我想我应该用匹配 action: (T) -> Unit
的东西替换 any()
,但我不知道该怎么做。
如果需要,我不介意使用交互器,但我至少需要按预期制作 forEach
运行 。你们能帮帮我吗?
此致,
佩德罗
我认为你根本不能模拟扩展函数,因为它们不是目标 class 的成员。
forEach
只是 Iterable
的外部助手
在这种情况下,您仍然会在 fooList
上调用 kotlin 的常规 forEach
。
而且我不明白模拟集合的动机是什么,尤其是用简单的 ArrayList
(listOf
) 代替模拟 OrderedBarCollection
的迭代器,这样做有什么要求?
解决方案是对模拟列表使用 thenAnswer
而不是 thenReturn
。
`when`(mockedList.iterator()).thenAnswer { fooList.iterator() }
原因:
作者:托拜厄斯伯杰
an iterator is only good for going through the list once. Therefore
you usually get a new one every time you call the iterator() function.
If you mock that with thenReturn(messageList.iterator()) , it will
just call that once on messageList and reuse that iterator instance
every time you try to get one for your mock. Once your first loop over
this iterator is finished, it will always say it has no more items.
With thenAnswer you define a supplier that is called each time your
mocked function is used, providing a new iterator for each call (as
would be expected)
对于下面给定的代码,在 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
}
我在上面根据这个问题的答案试过了:
我也试过:
com.nhaarman.mockito_kotlin.doCallRealMethod().`when`(mockedList).forEach(any())
但它导致:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
//...
Kotlin源码中forEach
的定义是:
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit
我想我应该用匹配 action: (T) -> Unit
的东西替换 any()
,但我不知道该怎么做。
如果需要,我不介意使用交互器,但我至少需要按预期制作 forEach
运行 。你们能帮帮我吗?
此致,
佩德罗
我认为你根本不能模拟扩展函数,因为它们不是目标 class 的成员。
forEach
只是 Iterable
在这种情况下,您仍然会在 fooList
上调用 kotlin 的常规 forEach
。
而且我不明白模拟集合的动机是什么,尤其是用简单的 ArrayList
(listOf
) 代替模拟 OrderedBarCollection
的迭代器,这样做有什么要求?
解决方案是对模拟列表使用 thenAnswer
而不是 thenReturn
。
`when`(mockedList.iterator()).thenAnswer { fooList.iterator() }
原因:
作者:托拜厄斯伯杰
an iterator is only good for going through the list once. Therefore you usually get a new one every time you call the iterator() function. If you mock that with thenReturn(messageList.iterator()) , it will just call that once on messageList and reuse that iterator instance every time you try to get one for your mock. Once your first loop over this iterator is finished, it will always say it has no more items. With thenAnswer you define a supplier that is called each time your mocked function is used, providing a new iterator for each call (as would be expected)