web-dev-qa-db-fra.com

Comment tester une fonction qui renvoie une observation en utilisant l'intervalle temporel dans rxjs 5?

Par exemple, j'ai une fonction comme celle-ci:

export function timeRange(start: number, end: number): Rx.Observable<number> {
  return Rx.Observable.interval(1000)
  .map(n => n + start)
  .take(end - start + 1)
}

Et j'ai eu un test unitaire qui a couru timeRange (10, 100) et a affirmé des valeurs contre elle.

Le problème est que les intervalles de temps rendent mon test trop long à exécuter.

Comment réduiriez-vous l'intervalle de temps sans toucher à la fonction elle-même?

J'ai essayé de lire les docs sur les planificateurs mais je ne les ai pas compris.

9
khoomeister

Il y a quelques mises en garde, mais vous pouvez tester votre fonction comme suit:

const Rx = require('rxjs');
const chai = require('chai');

function timeRange(start, end, interval = 1000, scheduler = Rx.Scheduler.async) {
  return Rx.Observable.interval(interval, scheduler)
    .map(n => n + start)
    .take(end - start + 1)
}

let scheduler = new Rx.TestScheduler(chai.assert.deepEqual);
let source = timeRange(2, 8, 50, scheduler);
let values = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8};
scheduler.expectObservable(source).toBe('-----2----3----4----5----6----7----(8|)', values);

scheduler.flush();

Quelques points à noter:

  • La fonction prend quatre arguments maintenant. L'intervalle et la Scheduler que nous devons utiliser pour passer la TestScheduler.

  • La TestScheduler a besoin d'une méthode pour comparer les objets en profondeur. Il sera utilisé pour comparer les tableaux d'objets Notification.

  • Vous ne pouvez pas utiliser 1000 car le temps maximum autorisé est codé en dur en tant que 750 . Notez que ceci est simplement du temps virtuel et n'est pas lié au temps réel, donc 50 que nous utilisons dans ce test n'est pas la même chose que 50ms. Nous avons juste besoin de nous situer dans ce délai 750.

  • Ensuite, les tests de marbre sont des tests de marbre typiques. Voir https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md pour plus d'informations. Sachez simplement que je ne peux pas utiliser les mêmes fonctions globales mocha que les opérateurs RxJS par défaut.

  • Je devais aussi spécifier les valeurs parce que les tests de marbre utilisent par défaut des chaînes et que je dois forcer des entiers pour assurer une égalité profonde.

Vous pouvez vérifier que cela échoue en modifiant une valeur de marbre:

let values = {'2': 42, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8};

Vous pouvez également voir quels sont les objets de notification en les imprimant sur la console:

let scheduler = new TestScheduler((actual, expected) => {
   console.log('Actual:', actual, '\n\n', 'Expected:', expected);
   chai.assert.deepEqual(actual, expected);
});

Utilisation de RxJS 5 mocha helpers

Pour le moment, RxJS 5 n'expose pas les assistants de test mocha. En fait, je l'utilise dans un autre projet sur lequel je travaille actuellement (y compris la génération d'images de diagramme). Vous pouvez jeter un coup d'œil ici https://github.com/martinsik/rxjs-extra en package.json quels scripts j'utilise. Cela fonctionne bien mais la configuration est un peu difficile à comprendre. Il s’agit de télécharger l’archive RxJS 5, de copier quelques fichiers et de la corriger avec un quelques fichiers . Ensuite, les options par défaut pour le test mocha sont définies avec mocha.opts qui est basé sur l'original de RxJS 5.

7
martin

J'ai récemment rencontré le même problème et découvert marbre testing qui vous permet d'écrire des tests visuels impressionnants qui rendent les tests Observable chronométrés extrêmement faciles.

Les résumés des tests de marbre prennent du temps et les tests s'exécutent instantanément (en utilisant TestScheduler sous le capot), mais vous pouvez toujours tester des processus complexes chronométrés. Ceci est un exemple de test pour vous donner une idée de la syntaxe:

it('should set up an interval', () => {
  const expected = '----------0---------1---------2---------3---------4---------5---------6-----';
  expectObservable(Observable.interval(100, rxTestScheduler)).toBe(expected, [0, 1, 2, 3, 4, 5, 6]);
});

Il s'agit en fait du test unitaire officiel à partir de Observable.interval du repo rxjs5: https://github.com/ReactiveX/rxjs/blob/master/spec/observables/interval-spec.ts

Consultez le documentation officielle pour plus d'informations.

Le faire fonctionner était un peu un défi, mais tout ce dont vous avez besoin, ce sont les deux fichiers marble-testing.ts et test-helper.ts de ce exemple de test de marbre .

3
magnattic

Vous créez soit une TestScheduler ou une VirtualTimeScheduler et le transmettez comme second argument facultatif à Observable.Interval . Dans votre cas, vous ajouteriez simplement un argument de planificateur facultatif à timeRange et transmettriez la valeur.

Ces planificateurs de test vous permettent de "passer du temps" sans attendre que le temps réel s'écoule.

Pour plus d'informations et d'exemples, voir Test de votre application Rx

3
Richard Szalay

Cela a très bien fonctionné pour moi: rxjs-testscheduler-compat . Du README:

rxjs-testscheduler-compat fournit l'interface de planificateur de tests de RxJS v4 à la version v5 de RxJS permet de migrer des scénarios de test existants avec un minimum d'effort, ainsi que d'écrire de nouveaux scénarios de test pour certains cas.

0
navels