rx-java
Тестирование устройства
Поиск…
замечания
Поскольку все методы 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) 😆)