Angular - Как правильно проверить действия, выполняемые в блоке подписки Observable? - PullRequest
0 голосов
/ 03 октября 2018

Я должен написать модульные тесты для угловых 5 приложений.Для этого я использую jasmine + jest (мы используем jest вместо кармы в моей компании для проверки скорости).

Чтобы проверить поведение моего компонента (см. Код ниже) ,Я создаю тест, который подписывается на тот же Observable, что и тестируемый компонент, затем подожду 2 секунды в надежде, что у блока кода подписки будет достаточно времени для завершения, а затем поищу внутренние изменения компонента.

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

  • Как бы вы справились с этой ситуацией?Я попытался посмотреть на async, но не смог найти способ, чтобы он соответствовал моим потребностям.
  • Как я могу убедиться, что мои тесты выполняются после блока подписки компонента?
  • Как можно избежать ожидания 2 секунд до начала теста и вместо этого просто дождаться завершения блока подписки компонента?

Заранее спасибо за помощь.


  • Компонент:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { SomeService } from './some.service';

@Component({
  selector: 'app-dummy',
  templateUrl: './dummy.component.html',
  styleUrls: ['./dummy.component.scss']
})
export class DummyComponent implements OnInit, OnDestroy {
  isEditable: Boolean;
  //...
  private aSubscriber;

  constructor(private someService: SomeService) {
    this.aSubscriber = someService.anObservable$.subscribe(value => {
      this.isEditable = value;
    });
  }

  ngOnInit() { }

  ngOnDestroy() {
    this.aSubscriber.unsubscribe();
  }
}
  • Сервис:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class SomeService {
  private aSubject = new Subject<any>();
  
  anObservable$ = this.aSubject.asObservable();
  
  constructor() { }

  notify(value) {
    this.aSubject.next(value);
  }
}
  • Файл спецификации:

import { async, ComponentFixture, TestBed, inject } from '@angular/core/testing';

import { DummyComponent } from './dummy.component';
import { SomeService } from './some.service';

describe('DummyComponent', () => {
  let component: DummyComponent;
  let fixture: ComponentFixture<DummyComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [DummyComponent],
      providers: [SomeService]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DummyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should subscribe to anObservable and set values according to the received one',
    inject([SomeService], (service: SomeService) => {
      service.anObservable$.subscribe(value => {
        setTimeout(() => { }, 2000);
        //Test that values are correctly set in the component under test.
        expect(component.isEditable).toBeTruthy();
        //...
      });

      service.notify(true);
  }));
});

1 Ответ

0 голосов
/ 03 октября 2018

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

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

Например, берете

  constructor(private someService: SomeService) {
    this.aSubscriber = someService.anObservable$.subscribe(value => {
      this.isEditable = value;
    });
  }

и рефакторинг:

  constructor(private someService: SomeService) {
    this.aSubscriber = someService.anObservable$.subscribe(value => {
      this.onValue(value);
    });
  }

  private onValue(value) {
    this.isEditable = value;
  }

Затем вы можете просто напрямую протестировать метод onValue, не проверяя Observable.По моему мнению, если вы не делаете что-то более сложное с вашим Observable (добавьте его в map (), filter () и т. Д.), Вам не нужно тестировать Observables, и вы удалите асинхронный аспект теста.

И если у вас есть продвинутый конвейер, вам, вероятно, стоит проверить его отдельно.Такое разбиение позволяет протестировать обе ситуации по отдельности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...