【问题标题】:Testing RxJava repeatWhen with Mockk returnsMany使用 Mockk 测试 RxJava repeatWhen 会返回Many
【发布时间】:2020-12-09 21:05:35
【问题描述】:

我正在尝试使用 Mockk 库测试多个服务器响应。类似于我在 this answer 中为 Mockito 找到的东西。

有我的示例 UseCase 代码,每隔几秒就会重复调用以从远程服务器加载系统,当远程系统包含的用户多于本地用户时,它会停止运行(执行onComplete)。

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 库模拟 cloudRepository.getSystem() 方法:

@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()
}

如您所见,我正在使用 returnsMany 答案,它应该在每次调用时返回不同的值。

主要问题是 returnsMany 每次都返回相同的第一个值,而 .takeUntil {} 永远不会成功,这意味着永远不会为此 Completable 调用 onComplete()。如何让returnsMany 在每次调用时返回不同的值?

【问题讨论】:

    标签: android unit-testing rx-java rx-java2 mockk


    【解决方案1】:

    您可能不明白.repeatWhen() 究竟是如何工作的。您希望每次请求重复时都会调用cloudRepository.getSystem(id)。这是不正确的。重复订阅一直在模拟 Single 的同一个实例上完成 - 在您的情况下首先是 Single.just(testSystemGetResponse)

    如何确保每次都调用getSystem()?将您的单曲包装成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()
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-16
      相关资源
      最近更新 更多