как выполнить модульное тестирование параллельного выполнения rxjava - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть два 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 голосов
/ 13 декабря 2018

Я действительно приложил усилия для реализации такого теста.

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

    }
}

В тестах одновременно запускается до 50 Completables на Schedulers.io(), каждый из которых вызывает logout().Есть счетчики, которые подсчитывают, сколько раз logout() успешно и неудачно.blockingAwait ожидает завершения всех завершений.Запустите этот тест 100 раз, и если вы удалите synchronized, он не будет выполнен в 20% случаев.onErrorComplete() существует для того, чтобы избежать распространения исключения до того, как все Completables завершат работу.

Интересный факт: если вы добавите getter и setter к loggedOut и используете его внутри logout(), то в большинстве случаев произойдет сбой без synchronized.

Надеюсь, это поможет!

...