rx-java
Enhetstestning
Sök…
Anmärkningar
Eftersom alla Schedulers-metoder är statiska, kan enhetstester med RxJava-krokar inte köras parallellt på samma JVM-instans. Om de var, skulle en TestScheduler tas bort i mitten av ett enhetstest. Det är i princip nackdelen med att använda Schedulers-klassen.
TestSubscriber
TestSubscribers tillåter dig att undvika arbetet med att skapa din egen prenumerant eller prenumerera Åtgärd <?> För att verifiera att vissa värden var levererade, hur många finns det, om Observera fullbordat, ett undantag togs upp och mycket mer.
Komma igång
Detta exempel visar bara en påstående att värdena 1,2,3 och 4 överfördes till observerbar via onNext.
TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
ts.assertValues(1,2,3,4); // Success
assertValues hävdar att räkningen är korrekt. Om du bara skulle passera några av värdena skulle påståendet misslyckas.
TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
ts.assertValues(1,2,3); // Fail
assertValues använder metoden equals när man gör påståenden. Detta låter dig enkelt testa klasser som behandlas som data.
TestSubscriber<Object> ts = TestSubscriber.create();
Observable.just(new Object(), new Object()).subscribe(ts);
ts.assertValues(new Object(), new Object()); // Fail
Detta exempel visar en klass som har en lika definierad och hävdar värdena från det observerbara.
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
Observera också att vi använder den kortare assertValue eftersom vi bara behöver kontrollera för en artikel.
Få alla händelser
Vid behov kan du också be om alla händelser som en lista.
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();
Att säga om händelser
Om du vill göra mer omfattande tester på dina evenemang kan du kombinera getOnNextEvents (eller getOn*Events ) med ditt favoritbibliotek:
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));
Testning Observable#error
Du kan se till att rätt undantagsklass släpps ut:
Observable<Integer> obs = Observable.error(new Exception("I am a Teapot"));
TestSubscriber<Integer> ts = new TestSubscriber<>();
obs.subscribe(ts);
ts.assertError(Exception.class);
Du kan också se till att det exakta undantaget kastades:
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 tillåter dig att kontrollera tid och körning av observerbara istället för att behöva göra upptagna väntningar, gå i trådar eller något för att manipulera systemtiden. Detta är mycket viktigt om du vill skriva enhetstester som är förutsägbara, konsekventa och snabba. Eftersom du manipulerar tiden, finns det inte längre chansen att en tråd har svallit, att ditt test misslyckas på en långsammare maskin eller att du slösar körningstiden upptagen med att vänta på ett resultat.
TestSchedulers kan tillhandahållas via överbelastningen som tar en schemaläggare för alla RxJava-operationer.
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 är ganska grundläggande. Det består bara av tre metoder.
testScheduler.advanceTimeBy(amount, timeUnit);
testScheduler.advanceTimeTo(when, timeUnit);
testScheduler.triggerActions();
Detta låter dig manipulera när TestScheduler ska avfyra alla åtgärder som avser någon tid i framtiden.
När du passerar schemaläggaren fungerar det inte så att TestScheduler ofta används på grund av hur ineffektivt det är. Att skicka schemaläggare till klasser slutar med att ge mycket extra kod för liten vinst. Istället kan du ansluta till RxJava's Schedulers.io () / beräkning () / etc. Detta görs med RxJava's Hooks. Detta låter dig definiera vad som kommer tillbaka från ett samtal från en av Schedulers-metoderna.
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;
}
}
Denna klass gör det möjligt för användaren att få testschemaläggaren som kommer att anslutas för alla samtal till schemalagare. Ett enhetstest behöver bara för att få denna schemaläggare i sin installation. Det rekommenderas starkt att man begär det i installationen och inte som något vanligt gammalt fält eftersom din TestScheduler kan försöka utlösa åtgärder från ett annat enhetstest när du förskriver tid. Nu blir vårt exempel ovan
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)
Det är så du effektivt kan ta bort systemklockan från ditt enhetstest (åtminstone när det gäller RxJava 😆)