Как да тествате RxJava?

1. Общ преглед

В тази статия ще разгледаме начини за тестване на код, написан с помощта на RxJava.

Типичният поток ние създаваме с RxJava се състои от видими и наблюдатели. Наблюдаемото е източник на данни, който е последователност от елементи. Един или повече наблюдатели се абонират за него, за да получават излъчени събития.

Обикновено наблюдателят и наблюдаемите се изпълняват в отделни нишки по асинхронен начин - което прави кода труден за тестване по традиционен начин.

За щастие RxJava предоставя клас TestSubscriber, който ни дава възможност да тестваме асинхронен поток, управляван от събития.

2. Тестване на RxJava - традиционният начин

Нека започнем с пример - имаме поредица от букви, които искаме да компресираме с поредица от цели числа от 1 включително.

Нашият тест трябва да твърди, че абонат, който слуша събития, излъчвани от компресиран наблюдаем, получава писма, ципирани с цели числа.

Написването на такъв тест по традиционен начин означава, че трябва да водим списък с резултати и да го актуализираме от наблюдател. Добавянето на елементи към списък с цели числа означава, че нашите наблюдаеми и наблюдателите трябва да работят в една и съща нишка - те не могат да работят асинхронно.

И така ще пропуснем едно от най-големите предимства на RxJava - обработка на събития в отделни нишки.

Ето как би изглеждала тази ограничена версия на теста:

List letters = Arrays.asList("A", "B", "C", "D", "E"); List results = new ArrayList(); Observable observable = Observable .from(letters) .zipWith( Observable.range(1, Integer.MAX_VALUE), (string, index) -> index + "-" + string); observable.subscribe(results::add); assertThat(results, notNullValue()); assertThat(results, hasSize(5)); assertThat(results, hasItems("1-A", "2-B", "3-C", "4-D", "5-E"));

Агрегираме резултатите от наблюдател, като добавяме елементи към списък с резултати . Наблюдателят и наблюдаемият работят в една и съща нишка, така че нашето твърдение се блокира правилно и чака методът Subscribe () да завърши.

3. Тестване на RxJava с помощта на TestSubscriber

RxJava идва с клас TestSubsriber, който ни позволява да напишем тестове, които работят с асинхронна обработка на събития. Това е нормален наблюдател, който се абонира за наблюдаемото.

В тест можем да изследваме състоянието на TestSubscriber и да направим твърдения за това състояние:

List letters = Arrays.asList("A", "B", "C", "D", "E"); TestSubscriber subscriber = new TestSubscriber(); Observable observable = Observable .from(letters) .zipWith( Observable.range(1, Integer.MAX_VALUE), ((string, index) -> index + "-" + string)); observable.subscribe(subscriber); subscriber.assertCompleted(); subscriber.assertNoErrors(); subscriber.assertValueCount(5); assertThat( subscriber.getOnNextEvents(), hasItems("1-A", "2-B", "3-C", "4-D", "5-E"));

Ние сме издържан TestSubscriber например до абонирате () метод на наблюдаемата. След това можем да изследваме състоянието на този абонат.

TestSubscriber има някои много полезни методи за твърдение , които ще използваме, за да потвърдим нашите очаквания. Абонатът трябва да получи 5 излъчени елемента от наблюдател и ние го твърдим, като извикаме метода assertValueCount () .

Можем да изследваме всички събития, получени от абонат, като извикаме метода getOnNextEvents () .

Извикването на метода assertCompleted () проверява дали е завършен поток, за който е абониран наблюдателят. Методът assertNoErrors () твърди, че няма грешки при абониране за поток.

4. Тестване на очаквани изключения

Понякога при нашата обработка, когато наблюдаем излъчва събития или наблюдател обработва събития, възниква грешка. В TestSubscriber има специален метод за изследване на държавната грешка - на () assertError метод, който се вида на изключение като аргумент:

List letters = Arrays.asList("A", "B", "C", "D", "E"); TestSubscriber subscriber = new TestSubscriber(); Observable observable = Observable .from(letters) .zipWith(Observable.range(1, Integer.MAX_VALUE), ((string, index) -> index + "-" + string)) .concatWith(Observable.error(new RuntimeException("error in Observable"))); observable.subscribe(subscriber); subscriber.assertError(RuntimeException.class); subscriber.assertNotCompleted();

Създаваме наблюдаемото, което се свързва с друго наблюдаемо, използвайки метода concatWith () . Второто наблюдаемо хвърля RuntimeException, докато излъчва следващо събитие. Можем да изследваме тип на това изключение на TestSubsciber, като извикаме метода assertError () .

Наблюдателят, който получи грешка, спира обработката и се оказва в незавършено състояние. Това състояние може да се провери чрез метода assertNotCompleted () .

5. Тестване на наблюдавано въз основа на времето

Да кажем, че имаме Observable, който излъчва едно събитие в секунда и искаме да тестваме това поведение с TestSubsciber .

Ние можем да се определи времето на базата на наблюдавани с помощта на Observable.interval () метод и се пропуска TIMEUNIT като аргумент:

List letters = Arrays.asList("A", "B", "C", "D", "E"); TestScheduler scheduler = new TestScheduler(); TestSubscriber subscriber = new TestSubscriber(); Observable tick = Observable.interval(1, TimeUnit.SECONDS, scheduler); Observable observable = Observable.from(letters) .zipWith(tick, (string, index) -> index + "-" + string); observable.subscribeOn(scheduler) .subscribe(subscriber);

В тик наблюдаемата ще издаде нова стойност всяка една секунда.

В началото на тест се намираме във време нула, така че нашият TestSubscriber няма да бъде завършен:

subscriber.assertNoValues(); subscriber.assertNotCompleted();

За да емулираме преминаването на времето в нашия тест, трябва да използваме клас TestScheduler . Можем да симулираме този пропуск от една секунда, като извикаме метода advanceTimeBy () в TestScheduler :

scheduler.advanceTimeBy(1, TimeUnit.SECONDS);

Методът advanceTimeBy () ще направи наблюдаемото произвеждане на едно събитие. Можем да твърдим, че едно събитие е произведено чрез извикване на метод assertValueCount () :

subscriber.assertNoErrors(); subscriber.assertValueCount(1); subscriber.assertValues("0-A");

Нашият списък с букви съдържа 5 елемента, така че когато искаме да накараме наблюдател да излъчва всички събития, трябва да минат 6 секунди обработка. За да емулираме тези 6 секунди, използваме метода advanceTimeTo () :

scheduler.advanceTimeTo(6, TimeUnit.SECONDS); subscriber.assertCompleted(); subscriber.assertNoErrors(); subscriber.assertValueCount(5); assertThat(subscriber.getOnNextEvents(), hasItems("0-A", "1-B", "2-C", "3-D", "4-E"));

След емулация на изминало време можем да изпълняваме твърдения на TestSubscriber . Можем да твърдим, че всички събития са произведени чрез извикване на метода assertValueCount () .

6. Заключение

В тази статия разгледахме начини за тестване на наблюдатели и наблюдаеми в RxJava. Разгледахме начин за тестване на излъчени събития, грешки и наблюдения, базирани на времето.

Изпълнението на всички тези примери и кодови фрагменти може да се намери в проекта GitHub - това е проект на Maven, така че трябва да е лесно да се импортира и да се изпълнява както е.