1
AS 4.0.2
RxBindings 4.0.0

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

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

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

在测试课中,我正在执行以下操作。将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)
}

非常感谢您的任何建议,

4

2 回答 2

3

你绝对不应该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'
于 2020-10-14T19:32:21.907 回答
1

如何在 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'

如果您使用库,我会说发布/订阅(RxJava)更具未来性。

我相信这将帮助您有一个良好的开端。

于 2020-10-22T08:16:36.040 回答