Поиск…


замечания

Поскольку все методы Schedulers статичны, модульные тесты, использующие крючки RxJava, не могут запускаться параллельно в одном экземпляре JVM. Если они, где один TestScheduler будет удален в середине единичного теста. В основном это недостаток использования класса Schedulers.

TestSubscriber

TestSubscribers позволяют избежать работы, создающей вашего собственного Абонента, или подписаться на Action <?>, Чтобы убедиться, что определенные значения, которые были доставлены, сколько есть, если Observable завершено, исключение было поднято и намного больше.

Начиная

Этот пример просто показывает утверждение, что значения 1,2,3 и 4, которые передаются в Observable через onNext.

TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
ts.assertValues(1,2,3,4); // Success

assertValues утверждает, что подсчет верен. Если вы должны были передавать только некоторые из значений, утверждение будет терпеть неудачу.

TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
ts.assertValues(1,2,3); // Fail

assertValues использует метод equals при выполнении assertValues . Это позволяет легко тестировать классы, которые рассматриваются как данные.

TestSubscriber<Object> ts = TestSubscriber.create();
Observable.just(new Object(), new Object()).subscribe(ts);
ts.assertValues(new Object(), new Object()); // Fail

В этом примере показан класс, который имеет равные значения и утверждает значения из Observable.

public class Room {

    public String floor;
    public String number;

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        }
        if (o instanceof Room) {
            Room that = (Room) o;
            return (this.floor.equals(that.floor))
                    && (this.number.equals(that.number));
        }
        return false;
    }
}

TestSubscriber<Room> ts = TestSubscriber.create();
Observable.just(new Room("1", "10")).subscribe(ts);
ts.assertValue(new Room("1", "10"); // Success

Также обратите внимание, что мы используем более короткий assertValue потому что нам нужно только проверить один элемент.

Получение всех событий

В случае необходимости вы также можете запросить все события в виде списка.

TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
List<Integer> onNextEvents = ts.getOnNextEvents();
List<Throwable> onErrorEvents = ts.getOnErrorEvents();
List<Notification<Integer>> onCompletedEvents = ts.getOnCompletedEvents();

Утверждение событий

Если вы хотите сделать более обширные тесты своих событий, вы можете комбинировать getOnNextEvents (или getOn*Events ) с вашей любимой библиотекой утверждений:

Observable<Integer> obs = Observable.just(1,2,3,4)
    .filter( x -> x % 2 == 0);

// note that we instanciate TestSubscriber via the constructor here 
TestSubscriber<Integer> ts = new TestSubscriber();
obs.subscribe(ts);

// Note that we are not using Observable#forEach here
// but java.lang.Iterable#forEach.
// You should never use Observable#forEach unless you know
// exactly what you're doing
ts.getOnNextEvents()
    .forEach( integer -> assertTrue(integer % 2 == 0));

Observable#error проверки Observable#error

Вы можете убедиться, что исправит правильный класс исключения:

Observable<Integer> obs = Observable.error(new Exception("I am a Teapot"));

TestSubscriber<Integer> ts = new TestSubscriber<>();
obs.subscribe(ts);

ts.assertError(Exception.class);

Вы также можете убедиться, что было выбрано точное исключение:

Exception e = new Exception("I am a Teapot");
Observable<Integer> obs = Observable.error(e);

TestSubscriber<Integer> ts = new TestSubscriber<>();
obs.subscribe(ts);

ts.assertError(e);

TestScheduler

TestSchedulers позволяет вам контролировать время и выполнение Observables вместо того, чтобы делать занятые ожидания, присоединять потоки или что-либо, чтобы манипулировать системным временем. Это ОЧЕНЬ важно, если вы хотите написать единичные тесты, которые являются предсказуемыми, последовательными и быстрыми. Поскольку вы манипулируете временем, нет больше шансов, что нить станет голодной, что ваш тест завершится неудачей на более медленной машине или что вы тратите время на занятие, ожидая результата.

TestSchedulers могут быть предоставлены через перегрузку, которая принимает Планировщик для любых операций RxJava.

TestScheduler testScheduler = new TestScheduler();
TestSubscriber<Integer> subscriber = TestSubscriber.create();
Observable.just(1,2,3)
          .delay(10, TimeUnit.SECONDS, testScheduler)
          .subscribe(subscriber);

try {
    Thread.sleep(TimeUnit.SECONDS.toMillis(11));
} catch (InterruptedException ignored) { }
subscriber.assertValues(1,2,3); // fails

testScheduler.advanceTimeBy(10, TimeUnit.SECONDS);
subscriber.assertValues(1,2,3); // success

TestScheduler довольно простой. Он состоит только из трех методов.

testScheduler.advanceTimeBy(amount, timeUnit);
testScheduler.advanceTimeTo(when, timeUnit);
testScheduler.triggerActions();

Это позволяет вам манипулировать, когда TestScheduler должен запускать все действия, относящиеся к некоторому времени в будущем.

При прохождении планировщика это не так, как обычно используется TestScheduler из-за того, насколько он неэффективен. Передача планировщиков в классы заканчивается предоставлением большого количества дополнительного кода для небольшого выигрыша. Вместо этого вы можете подключиться к плагину RxJava Schedulers.io () / computation () / etc. Это делается с помощью крючков RxJava. Это позволяет вам определить, что возвращается от вызова от одного из методов Schedulers.

public final class TestSchedulers {

    public static TestScheduler test() {
        final TestScheduler testScheduler = new TestScheduler();
        RxJavaHooks.reset();
        RxJavaHooks.setOnComputationScheduler((scheduler) -> {
            return testScheduler;
        });
        RxJavaHooks.setOnIOScheduler((scheduler) -> {
            return testScheduler;
        });
        RxJavaHooks.setOnNewThreadScheduler((scheduler) -> {
            return testScheduler;
        });
        return testScheduler;
    }
}

Этот класс позволяет пользователю получить планировщик тестирования, который будет подключен для всех вызовов Планировщиков. Единичный тест просто должен был получить этот планировщик в его настройке. Настоятельно рекомендуется использовать его в настройке, а не как любое обычное старое поле, потому что ваш TestScheduler может попытаться вызвать триггер из другого модульного теста, когда вы продвигаете время. Теперь наш пример выше становится

TestScheduler testScheduler = new TestScheduler();
TestSubscriber<Integer> subscriber = TestSubscriber.create();
Observable.just(1,2,3)
          .delay(10, TimeUnit.SECONDS, testScheduler)
          .subscribe(subscriber);
testScheduler.advanceTimeBy(9, TimeUnit.SECONDS);
subscriber.assertValues(); // success (delay hasn't finished)
testScheduler.advanceTimeBy(10, TimeUnit.SECONDS);
subscriber.assertValues(1,2,3); // success (delay has finished)

Вот как вы можете эффективно удалить системные часы из вашего модульного теста (по крайней мере, до RxJava) 😆)



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow