rx-java
Examen de la unidad
Buscar..
Observaciones
Debido a que todos los métodos de Programadores son estáticos, las pruebas unitarias que utilizan los enganches RxJava no se pueden ejecutar en paralelo en la misma instancia de JVM. Si estuvieran donde, un TestScheduler se eliminaría en medio de una prueba de unidad. Esa es básicamente la desventaja de usar la clase Schedulers.
Suscriptor de prueba
Los Suscriptores de Prueba le permiten evitar el trabajo creando su propio Suscriptor o Acción de suscripción <?> Para verificar que ciertos valores se entregaron, cuántos hay, si el Observable se completó, se generó una excepción y mucho más.
Empezando
Este ejemplo solo muestra una afirmación de que los valores 1,2,3 y 4 se transfirieron al Observable a través de onNext.
TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
ts.assertValues(1,2,3,4); // Success
assertValues afirma que el recuento es correcto. Si solo pasara algunos de los valores, la afirmación fallaría.
TestSubscriber<Integer> ts = TestSubscriber.create();
Observable.just(1,2,3,4).subscribe(ts);
ts.assertValues(1,2,3); // Fail
assertValues utiliza el método equals cuando hace aserciones. Esto le permite probar fácilmente las clases que se tratan como datos.
TestSubscriber<Object> ts = TestSubscriber.create();
Observable.just(new Object(), new Object()).subscribe(ts);
ts.assertValues(new Object(), new Object()); // Fail
Este ejemplo muestra una clase que tiene un igual definido y afirma los valores del 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
También tenga en cuenta que usamos assertValue más assertValue porque solo necesitamos verificar un elemento.
Conseguir todos los eventos
Si es necesario, también puede solicitar todos los eventos como una 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();
Afirmación de eventos
Si desea realizar pruebas más exhaustivas en sus eventos, puede combinar getOnNextEvents (u getOn*Events ) con su biblioteca de aserción favorita:
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));
Prueba de Observable#error
Puede asegurarse de que se emita la clase de excepción correcta:
Observable<Integer> obs = Observable.error(new Exception("I am a Teapot"));
TestSubscriber<Integer> ts = new TestSubscriber<>();
obs.subscribe(ts);
ts.assertError(Exception.class);
También puede asegurarse de que se haya lanzado la excepción exacta:
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 le permite controlar el tiempo y la ejecución de los Observables en lugar de tener que hacer esperas ocupadas, unir hilos o cualquier cosa para manipular la hora del sistema. Esto es MUY importante si desea escribir pruebas unitarias que sean predecibles, consistentes y rápidas. Debido a que está manipulando el tiempo, ya no existe la posibilidad de que un subproceso se pierda de hambre, que su prueba falle en una máquina más lenta o que pierda el tiempo de ejecución ocupado esperando un resultado.
TestSchedulers se puede proporcionar a través de la sobrecarga que toma un Programador para cualquier operación de 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
El TestScheduler es bastante básico. Solo consiste en tres métodos.
testScheduler.advanceTimeBy(amount, timeUnit);
testScheduler.advanceTimeTo(when, timeUnit);
testScheduler.triggerActions();
Esto le permite manipular cuando el TestScheduler debe disparar todas las acciones correspondientes a algún tiempo en el futuro.
Si bien el paso del programador funciona, no es así como se usa comúnmente el TestScheduler debido a su ineficacia. Pasar programadores a clases termina proporcionando una gran cantidad de código adicional para obtener poca ganancia. En su lugar, puede conectarse a los Schedulers.io () / computation () / etc de RxJava. Esto se hace con los ganchos de RxJava. Esto le permite definir lo que se devuelve de una llamada desde uno de los métodos de los programadores.
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;
}
}
Esta clase permite al usuario obtener el programador de prueba que se conectará para todas las llamadas a los programadores. Una prueba de unidad solo necesitaría tener este programador en su configuración. Se recomienda encarecidamente adquirirlo en la configuración y no como un campo antiguo, ya que su TestScheduler podría intentar activar Acciones desde otra prueba de unidad cuando avance el tiempo. Ahora nuestro ejemplo anterior se convierte en
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)
Así es como puede eliminar efectivamente el reloj del sistema de su prueba de unidad (al menos en lo que respecta a RxJava 😆)