Testing Observables - проверка на побочные эффекты при подписке - PullRequest
0 голосов
/ 25 января 2019

Я хочу проверить, как наблюдаемое будет вести себя с точки зрения потребителя.

Я не могу сказать, будут ли побочные эффекты, когда я подпишусь (холодная) или нет (горячая).

Есть ли способ проверить это поведение в модульном тесте?

У меня есть TestScheduler из rxjs / testing, но я не вижу хорошего способа проверить числораз наблюдаемое было создано.

// ...the create method has been mocked to emit after 3 frames
const create$ = api.create(potato).pipe(
  tap(console.log.bind(null, 'object created'))
);
create$.subscribe();
create$.subscribe();
create$.subscribe();

// Test how many times create$ has gotten a subscription, generated a cold observable, and completed.

const timing = '---(a|)'; // wait 3 frames, emit value of `a`, complete
const values = { a: potato };
expectObservable(create$).toBe(timing, values);

Этот тест проходит успешно, но сообщение "объект создан" запускается четыре раза (3 для моих подписчиков и одно из промежуточного программного обеспечения).

IЯ хочу написать неудачный тест (истинно отрицательный), прежде чем изменить поведение наблюдаемой так, чтобы оно соответствовало желаемому для api.create.

Как проверить, что поведение создания выполняется только один раз?

Я пробовал:

  • spyOn, но фактический метод создания вызывается только один раз.
  • Array.isArray(create$.observers) - слишком косвенный, только проверяет, горячий ли он, не, если он ведет себя как ожидалось.
  • tap(() => runCount++) \ expect(runCount).toBe(1) - работает, если я сбрасываюПланировщик, но кажется вне нормы для тестирования rxjs.
  • Использование Observable.create с заводской функцией для ручного отслеживания количества выполнений.Также работает, несколько многословно.

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Вот лучший способ, который я нашел на данный момент, чтобы проверить в модульном тесте, что внутренняя наблюдаемая вызывается только один раз для каждой подписки.

  1. Создать поддельную холодную наблюдаемую, которая действует как ваша фактическаяоперация
  2. Используйте spyOn для возврата этого значения из вашей функции "сделайте реальную работу"
  3. Вызовите внешний API
  4. Проверьте runCount на поддельной наблюдаемой холоде
scheduler.run(rx => {
  let runCount = 0;
  const timing = '---(a|)';
  const values = { a: {x:42} };

  // This represents the inner cold observable.
  // We want to validate that it does/does not get called once per subscription
  const mockedCreate$ = rx.cold(timing, values).pipe(
    tap(() => runCount++),
  );
  spyOn(api, 'doCreate').and.returnValue(mockedCreate$);

  const create$ = api.create({x:42}); // internally, calls doCreate
  create$.subscribe();
  create$.subscribe();
  create$.subscribe();
        // Explanation:
        // If api.create wasn't multicasting/sharing the result of the doCreate
        // operation, we'd see multiple actual save operations, not just 1

  rx.expectObservable(create$).toBe(timing, values);
  scheduler.flush();
  expect(runCount).toBe(1, 'how often the "real" create operation ran');
});
0 голосов
/ 25 января 2019

Я не уверен, что следую тому, что вы просите, но я могу ответить на ваше беспокойство по поводу того, сколько раз создается ваша наблюдаемая:

Один раз.

const create$ = api.create(potato)

Это создаетваша наблюдаемая.Ваше .pipe приложение к наблюдаемой является частью пути данных от точки наблюдения к подписчикам.

potato ---(pipe)--->.subscribe()
     +----(pipe)--->.subscribe()
     +----(pipe)--->.subscribe()
     +----(pipe)--->(expectObservable inspection)

Вместо этого может показаться, что вам может понадобиться добавить дополнительный канал для обменарезультат.Возможно, неудивительно, что эта труба называется share.

Вход

import { Observable, Subject } from 'rxjs';
import { share, tap } from 'rxjs/operators';

let obj: Subject<string> = new Subject<string>();
let obs: Observable<string> = obj.pipe(tap(() => console.log('tap pipe')));

obs.subscribe((text) => console.log(`regular: ${text}`));
obs.subscribe((text) => console.log(`regular: ${text}`));
obs.subscribe((text) => console.log(`regular: ${text}`));

let shared: Observable<string> = obs.pipe(share());

shared.subscribe((text) => console.log(`shared: ${text}`));
shared.subscribe((text) => console.log(`shared: ${text}`));
shared.subscribe((text) => console.log(`shared: ${text}`));

obj.next('Hello, world!');

Выход

tap pipe
regular: Hello, world!
tap pipe
regular: Hello, world!
tap pipe
regular: Hello, world!
tap pipe
shared: Hello, world!
shared: Hello, world!
shared: Hello, world!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...