Модульный тест Тема: Невозможно прочитать свойство «отписаться» от неопределенного - PullRequest
2 голосов
/ 27 января 2020

После того, как я добавил Subject в свою службу и подписался на него в своем компоненте, все тесты для этого компонента терпят неудачу с

Cannot read property 'unsubscribe' of undefined

Мне интересно
- почему all тесты для этого компонента не пройдены, и
- как проверить субъект, его метод next () и подписку, как показано ниже в Angular 8.

Компонент:

export class TrackerComponent implements OnInit, OnDestroy {
  trackSubscription: Subscription;

  constructor(private trackerService: TrackerService) { }

  ngOnInit() {
    this.trackSubscription = this.trackerService.trackSubject.subscribe((state) => {
      console.log(state);
    });
  }

  startTracking() { // called by clicking html button
    this.trackerService.start();
  }

  ngOnDestroy() {
    this.trackSubscription.unsubscribe();
  }
}

Сервис:

export class TrackerService {
   trackSubject = new Subject<boolean>();

   start() {
       // do stuff
       this.trackSubject.next(true);
   }
}

Тест:

describe('TrackerComponent', () => {
  let component: TrackerComponent;
  let fixture: ComponentFixture<TrackerComponent>;
  let trackerService: jasmine.SpyObj<TrackerService>;

  // helper function
  const el = (selector) => fixture.nativeElement.querySelector(selector);

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [TrackerComponent],
      providers: [
        { provide: TrackerService, useFactory: () => spyOnClass(TrackerService) }
      ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TrackerComponent);
    component = fixture.componentInstance;
    trackerService = TestBed.get(TrackerService);
    fixture.detectChanges();
  });


  // it should show a start button
  it('should show a start button', () => {
    expect(el('[data-test="start-btn"]')).toBeTruthy();
  });

  it('should call tracker service when start button clicked', async(() => {
    el('[data-test="start-btn"]').click();

    fixture.whenStable().then(() => {
      expect(trackerService.startTracking).toHaveBeenCalled();
    });
  }));
});

Ответы [ 2 ]

1 голос
/ 27 января 2020

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

 ngOnDestroy() {
  if(this.trackSubscription){
    this.trackSubscription.unsubscribe();
  }
}

Если проблема возникает во время выполнения тестовых случаев

 it('calls ngOnDestroy method', () => {
    component.trackSubscription= new Subscription();
    spyOn(component.trackSubscription, 'unsubscribe');
    component.ngOnDestroy();
    expect(component.trackSubscription.unsubscribe).toHaveBeenCalled();
  });

Надеюсь, это поможет!

0 голосов
/ 28 января 2020

Мои тесты проходят, когда я делаю это в тесте - но не уверен, имеет ли это смысл, так как я совсем новичок в модульном тестировании.

В перед каждым Я создаю тему и подписка:

component.trackSubscription = new Subscription();
trackerService.trackSubject = new Subject<boolean>();

, а затем фактические тесты:

it('should subscribe trackSubscription to service subject', () => {
    component.trackSubscription = trackerService.trackSubject.subscribe();
    spyOn(trackerService.trackSubject, 'subscribe');
    component.ngOnInit();
    expect(trackerService.trackSubject.subscribe).toHaveBeenCalled();
  });

  it('unsubscribes the trackSubscription', () => {

    spyOn(component.trackSubscription, 'unsubscribe');
    component.ngOnDestroy();
    expect(component.trackSubscription.unsubscribe).toHaveBeenCalled();
  });

РЕДАКТИРОВАТЬ: на самом деле просто объявить тему и подписку перед каждым, чтобы пройти весь тест, но я думаю, это не мешает также тестировать (не) методы подписки.

...