问题描述
我正在尝试使用Mockk库测试多个服务器响应。就像我在this answer中找到的Mockito一样。
我有一个示例UseCase代码,每隔几秒钟重复一次从远程服务器加载系统的调用,并且当远程系统包含的用户多于本地用户时,它将停止运行(@H_502_3@onComplete)。
@H_502_3@override fun execute(localSystem: System,delay: Long): Completable { return cloudRepository.getSystem(localSystem.id) .repeatWhen { repeatHandler -> // Repeat every [delay] seconds repeatHandler.delay(params.delay,TimeUnit.SECONDS) } .takeuntil { // Repeat until remote count of users is greater than local count return@takeuntil it.users.count() > localSystem.users.count() } .ignoreElements() // Ignore onNext() calls and wait for onComplete()/onError() call }
要测试此行为,我在Mockk库中模拟@H_502[email protected]stem()方法:
@H_502_3@@Test fun testListeningEnds() { every { getSystem(TEST_SYstem_ID) } returnsMany listof( Single.just(testSystemGetResponse),// return the same amount of users as local system has Single.just(testSystemGetResponse),// return the same amount of users as local system has Single.just( // return the greater amount of users as local system has testSystemGetResponse.copy( owners = listof( TEST_USER,TEST_USER.copy(id = UUID.randomUUID().toString()) ) ) ) ) useCase.execute( localSystem = TEST_SYstem,delay = 3L ) .test() .await() .assertComplete() }
如您所见,我正在使用@H_502_3@returnsMany答案,该答案应在每次通话时返回不同的值。
主要问题是@H_502_3@returnsMany每次都返回相同的第一个值,而@H_502_3@.takeuntil {}永不成功,这意味着从未为该Completable调用@H_502_3@onComplete()。如何使@H_502_3@returnsMany在每次通话中返回不同的值?
解决方法
您可能不了解.repeatWhen()
的工作原理。您希望每次请求重复时都会调用cloudRepository.getSystem(id)
。那是不对的。重复预订始终在模拟Single
的同一实例上进行–在您的情况下,第一个Single.just(testSystemGetResponse)
。
如何确保getSystem()
每次都被调用?将您的Single包装到Single.defer()
中。它类似于Single.fromCallable()
,但是所传递的lambda的返回类型之间存在差异。传递给.defer()
运算符的Lambda必须返回Rx类型(在本例中为Single)。
最终实现(我进行了一些更改以使其能够成功编译):
data class User(val id: String)
data class System(val users: List<User>,val id: Long)
class CloudRepository {
fun getSystem(id: Long) = Single.just(System(mutableListOf(),id))
}
class SO63506574(
private val cloudRepository: CloudRepository
) {
fun execute(localSystem: System,delay: Long): Completable {
return Single.defer { cloudRepository.getSystem(localSystem.id) } // <-- defer
.repeatWhen { repeatHandler ->
repeatHandler.delay(delay,TimeUnit.SECONDS)
}
.takeUntil {
return@takeUntil it.users.count() > localSystem.users.count()
}
.ignoreElements()
}
}
并测试(约8秒后成功):
class SO63506574Test {
@Test
fun testListeningEnds() {
val TEST_USER = User("UUID")
val TEST_SYSTEM = System(mutableListOf(),10)
val repository = mockk<CloudRepository>()
val useCase = SO63506574(repository)
val testSystemGetResponse = System(mutableListOf(),10)
every { repository.getSystem(10) } returnsMany listOf(
Single.just(testSystemGetResponse),// return the same amount of users as local system has
Single.just(testSystemGetResponse),// return the same amount of users as local system has
Single.just( // return the greater amount of users as local system has
testSystemGetResponse.copy(
users = listOf(
TEST_USER,TEST_USER.copy(id = UUID.randomUUID().toString())
)
)
)
)
useCase.execute(
localSystem = TEST_SYSTEM,delay = 3L
)
.test()
.await()
.assertComplete()
}
}