单元测试以检查在使用 RxBindings 时是否调用了 accept

Unit testing to check that the accept was called when using RxBindings

AS 4.0.2
RxBindings 4.0.0

我已经编写了一个单元测试来测试是否调用了使用 jakeWartons rxBindings 的 PublishRelay accept

这是我正在测试的代码片段

private val checkStoresRelay: Relay<Unit> = PublishRelay.create<Unit>()

private fun onCheckStockTapped(view: View) {
    view.textViewCheckStock
        .clicks()
        .debounce(TIME_OUT, TimeUnit.MILLISECONDS)
        .subscribeBy(
            onNext = checkStoresRelay::accept,
            onError = { Timber.e(it, it.localizedMessage) }
        )
}

在测试中class我正在做以下事情。 textViewCheckStock.performClick() 将触发,我检查 checkStoresRelay.accept(Unit) 是否已被调用。

但我不确定 availableDeliveryOptionsModel.checkStoresRelay.accept(Unit) 因为我认为我不应该在测试中调用它。但是,如果我删除它,测试将失败。只是想知道测试这个的最佳方法是什么?

@Test
fun `should check stores when checkStock is tapped`() {
    // Arrange
    val viewHolder = createViewHolder()
    availableDeliveryOptionsModel.bind(viewHolder)
    val actual = availableDeliveryOptionsModel.checkStoresRelay.test()

    // Act
    availableDeliveryOptionsModel.checkStoresRelay.accept(Unit)
    viewHolder.itemView.textViewCheckStock.performClick()

    // Assert
    actual.assertValue(Unit)
}

非常感谢您的任何建议,

绝对不应该在测试中直接调用 relay.accept()accept 应在 subscribeBy() 中代表您调用。问题是基于 .debounce() 运算符。

Debounce 等待给定的时间,如果没有后续发射(查看点击),它会向下游发射项目(进入 .subscribeBy())。这会产生一些延迟并导致测试失败,因为 actual.assertValue(Unit) 在 单击(发出)之前被调用

您可以使用 RxSchedulerRule 解决此问题。 debounce 操作符的执行是在当前线程上立即完成的,所以你基本上会处理项目传递到中继和之后的 运行 断言。

我已经稍微简化了您的示例,但我希望要点仍然存在:

class SO64328289 {
    val checkStoresRelay: Relay<Unit> = PublishRelay.create()

    fun onCheckStockTapped(view: View) {
        view.clicks()
            .debounce(1, TimeUnit.MILLISECONDS)
            .subscribeBy(
                onNext = checkStoresRelay::accept,
                onError = { Log.e("SO64328289", it.localizedMessage) }
            )
    }
}

@RunWith(RobolectricTestRunner::class)
@Config(sdk = [28])
class SO64328289Test {

    @get:Rule val schedulerRule = RxSchedulerRule()

    @Test
    fun `when button clicked then relay emits value`() {
        val tested = SO64328289()
        val view = View(ApplicationProvider.getApplicationContext())

        tested.onCheckStockTapped(view)
        val relayTestSubscription = tested.checkStoresRelay.test()

        view.performClick()

        relayTestSubscription.assertValue(Unit)
    }
}

我用过Robolectric,但它应该也适用于其他测试框架。如果您想自己尝试,这些是我在测试项目中使用的依赖项:

implementation 'com.jakewharton.rxbinding3:rxbinding:3.1.0'
implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.1'
implementation "io.reactivex.rxjava2:rxkotlin:2.4.0"
implementation "io.reactivex.rxjava2:rxjava:2.2.20"

testImplementation 'com.github.Plastix.RxSchedulerRule:rx2:1.0.2' // requires jitpack.io maven
testImplementation 'org.robolectric:robolectric:4.4'
testImplementation 'junit:junit:4.13.1'
testImplementation 'androidx.test:core:1.3.0'

如何在 android.

的库模块中监听事件

唯一的方法是将您自己的侦听器或事件或发布和订阅框架添加到模块。无论如何你都需要这样做。

对于事件使用像

这样的 EventBus

https://github.com/greenrobot/EventBus

// RX Java/Android
compile 'io.reactivex:rxjava:1.1.0'
// https://github.com/ReactiveX/RxAndroid
compile 'io.reactivex:rxandroid:1.1.0'
// https://github.com/JakeWharton/RxBinding/
compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'

我会说 publish/subscribe (RxJava) 如果您使用的是库,它更适合未来。

我相信这会帮助你有个好的开始。