rx-java
Testów jednostkowych
Szukaj…
Uwagi
Ponieważ wszystkie metody programu planującego są statyczne, testów jednostkowych wykorzystujących haki RxJava nie można uruchamiać równolegle w tej samej instancji JVM. Jeśli tak, jeden TestScheduler zostanie usunięty w trakcie testu jednostkowego. Jest to w zasadzie wada korzystania z klasy Schedulers.
TestSubscriber
TestSubscribers pozwalają uniknąć pracy związanej z tworzeniem własnego subskrybenta lub subskrybować akcję <?>, Aby sprawdzić, czy pewne wartości zostały dostarczone, ile ich jest, jeśli Obserwowalność zakończona, wyjątek został zgłoszony i wiele więcej.
Pierwsze kroki
Ten przykład pokazuje po prostu twierdzenie, że wartości 1,2,3 i 4 zostały przekazane do Observable przez onNext.
TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
ts.assertValues(1,2,3,4); // Success
assertValues zapewnia, że liczba jest poprawna. Jeśli miałbyś przekazać tylko niektóre wartości, aser nie powiedzie się.
TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
ts.assertValues(1,2,3); // Fail
assertValues używa metody equals . Umożliwia to łatwe testowanie klas, które są traktowane jako dane.
TestSubscriber<Object> ts = TestSubscriber.create();
Observable.just(new Object(), new Object()).subscribe(ts);
ts.assertValues(new Object(), new Object()); // Fail
Ten przykład pokazuje klasę, która ma zdefiniowaną wartość równości i która potwierdza wartości z 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
Pamiętaj też, że używamy krótszej wartości assertValue ponieważ musimy sprawdzić tylko jeden element.
Zdobywanie wszystkich wydarzeń
W razie potrzeby możesz również poprosić o wszystkie wydarzenia jako listę.
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();
Zapewnianie wydarzeń
Jeśli chcesz przeprowadzić bardziej szczegółowe testy swoich wydarzeń, możesz połączyć getOnNextEvents (lub getOn*Events ) z ulubioną biblioteką asercji:
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));
Testowanie Observable#error
Możesz upewnić się, że emitowana jest poprawna klasa wyjątków:
Observable<Integer> obs = Observable.error(new Exception("I am a Teapot"));
TestSubscriber<Integer> ts = new TestSubscriber<>();
obs.subscribe(ts);
ts.assertError(Exception.class);
Możesz także upewnić się, że zgłoszony został wyjątek:
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 pozwala kontrolować czas i wykonywanie Obserwowalnych zadań zamiast robić zajęte oczekiwania, dołączać do wątków lub cokolwiek innego, aby manipulować czasem systemowym. Jest to BARDZO ważne, jeśli chcesz pisać testy jednostkowe, które są przewidywalne, spójne i szybkie. Ponieważ manipulujesz czasem, nie ma już szansy, że wątek się zagłodzi, że test nie powiedzie się na wolniejszej maszynie lub że marnujesz czas na wykonanie czekając na wynik.
TestSchedulers można dostarczyć przez przeciążenie, które zajmuje program planujący dla dowolnych operacji 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 jest dość prosty. Składa się tylko z trzech metod.
testScheduler.advanceTimeBy(amount, timeUnit);
testScheduler.advanceTimeTo(when, timeUnit);
testScheduler.triggerActions();
Pozwala to manipulować, kiedy TestScheduler powinien uruchamiać wszystkie działania dotyczące pewnego czasu w przyszłości.
Podczas przekazywania harmonogramu działa, nie jest to tak często używany TestScheduler ze względu na jego nieskuteczność. Przekazywanie harmonogramów do klas daje w efekcie dużo dodatkowego kodu dla małego zysku. Zamiast tego możesz podłączyć się do Schedulers.io () / computation () / etc w RxJava. Odbywa się to za pomocą Haków RxJava. Pozwala to określić, co zostanie zwrócone z połączenia z jednej z metod programu planującego.
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;
}
}
Ta klasa pozwala użytkownikowi uzyskać harmonogram testowy, który zostanie podłączony do wszystkich połączeń z programami planującymi. Test jednostkowy wymagałby tylko skonfigurowania tego harmonogramu. Zdecydowanie zaleca się pozyskanie go w ustawieniach, a nie jak w zwykłym starym polu, ponieważ twój TestScheduler może próbować wyzwalać funkcje z innego testu jednostkowego, gdy przyspieszysz czas. Teraz nasz powyższy przykład staje się
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)
W ten sposób możesz skutecznie usunąć zegar systemowy z testu jednostkowego (przynajmniej jeśli chodzi o RxJava 😆)