如何对并发的rxjava执行进行单元测试

时间:2018-12-13 09:14:19

标签: java junit kotlin rx-java2 mockk

我有两个Completable同时在两个不同的线程上运行并访问共享资源。我想测试它们的行为,以便只有第一个运行某些代码,而第二个运行却有错误。

由于我在测试中使用Scheduler.trampoline(),所以两个Completable不能同时运行,而是按顺序运行,因此我无法对该代码进行单元测试。

示例

    val subscription = userRepository.logout().test()
    val subscriptionSimultaneous = userRepository.logout().test()


    subscription
        .assertNoErrors()
        .assertComplete()

    subscriptionSimultaneous
        .assertError(someError)
        .assertNotComplete()

    verify(exactly = 1) { somethingThatMustRunOnlyOnce() }

1 个答案:

答案 0 :(得分:1)

我实际上是在努力进行这样的测试。

public class RxTest {
    @Test
    public void testConcurrency() {
        Logout logout = new Logout();

        AtomicInteger logoutCount = new AtomicInteger(0);
        AtomicInteger errorCount = new AtomicInteger(0);

        Completable logoutCompletable = Completable.fromAction(() -> logout.logout())
                .subscribeOn(Schedulers.io())
                .doOnComplete(() -> logoutCount.addAndGet(1))
                .doOnError(error -> errorCount.addAndGet(1))
                .onErrorComplete();
        int tries = 50;
        Completable[] arrayOfLogoutCompletables = new Completable[tries];
        for (int i = 0; i < tries; i++) {
            arrayOfLogoutCompletables[i] = logoutCompletable;
        }
        // run all in parallel and wait for all to finish
        Completable.mergeArray(arrayOfLogoutCompletables).blockingAwait();

        assertEquals(1,logoutCount.get());
        assertEquals(tries - 1, errorCount.get());
    }


    private static class Logout {
        private boolean loggedOut = false;

        /**
         * if you remove synchronized test will fail!!
         */
        private synchronized void logout() {
            if (loggedOut) throw new IllegalStateException();
            loggedOut = true;
        }

    }
}

测试在Schedulers.io()上同时运行多达50个Completables,每个测试都调用logout()。有些计数器可以计算logout()成功和失败的次数。 blockingAwait正在等待所有Completables完成。 运行此测试100次,如果您删除synchronized,它可能会在20%的时间内失败。 onErrorComplete()可以避免在所有Completables完成之前传播异常。

有趣的事实:如果将getter和setter添加到loggedOut并在logout()中使用它,那么在大多数情况下,如果没有synchronized,它将失败。

希望有帮助!