使用Jasmine fakeAsync和tick测试基于计时器的代码

时间:2018-07-17 15:30:06

标签: angular jasmine

我有一项服务,可以每隔一秒钟轮询一次端点:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { timer, Observable, BehaviorSubject } from 'rxjs';
import { includes, isEqual } from 'lodash';

@Injectable({
  providedIn: 'root'
})

export class CardService {
  private pollInstance: Observable<number>;
  private card: IContactlessCard = undefined;
  private pollingEnabled = true;

  public listen: BehaviorSubject<any> = new BehaviorSubject(undefined);

  constructor(private http: HttpClient) {
    this.pollInstance = timer(1000);
  }

  private handleCardRemovedEvent = () => {
    this.card = undefined;
    console.log('Card removed from reader');
  }

  private handleCardDetectedEvent = (response) => {
    console.log('Card detected');
    this.card = response;
    this.listen.next({
      card: this.card
    });
  }

  private handleCardStilPresentEvent = () => {
    console.log('Card still present');
  }

  private restartPoll = () => {
    if (this.pollingEnabled) {
      this.pollInstance.subscribe(() => {
        this.pollCardStatus();
      });
    }
  }

  public pollCardStatus = () => {
    console.log('pollCardStatus...');
    this.pollingEnabled = true;
    this.http.get('http://someendpoint:1234/card').subscribe((response: any) => {
      if (!response) {
        if (this.card) {
          this.handleCardRemovedEvent();
        }

        this.restartPoll();
        return;
      }

      if (!isEqual(this.card, response)) {
        this.handleCardDetectedEvent(response);
      } else {
        this.handleCardStilPresentEvent();
      }

      this.restartPoll();
    }, (error) => {
      this.restartPoll();
    });
  }

  public stopPolling = () => {
    console.log('Card polling cancelled');
    this.pollingEnabled = false;
  }

}

我说的是'poll',但是从代码中可以看到,有一个pollCardStatus函数,它是向该服务上的端点发起请求的入口,在处理了响应之后,呼叫restartPoll,等待一秒钟,然后再次呼叫pollCardStatus

我现在可以编写单元测试了,到目前为止,我可以使用以下测试规范来介绍handleCardDetectedEvent逻辑:

import { CardService } from './card.service';
import { TestBed, getTestBed, fakeAsync, tick } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

describe('CardService Tests:', () => {
  let cardService: CardService;
  let injector: TestBed;
  let httpMock: HttpTestingController;
  let req;

  const mockCardResponse = {
    'type': 'SOME_CARD',
    'uid': 'xxx-111-222-ZZZ'
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [CardService]
    });
    injector = getTestBed();
    cardService = injector.get(CardService);
    httpMock = injector.get(HttpTestingController);
  });

  afterEach(() => {
    httpMock.verify();
  });

  describe('when polling for card status changes', () => {
    beforeEach(() => {
      cardService.pollCardStatus();
      req = httpMock.expectOne('http://someendpoint:1234/card');
        expect(req.request.method).toBe('GET');
    });
    describe('and a new card is detected', () => {
      beforeEach(() => {
        req.flush(mockCardResponse);
      });
      it('should be able inspect the card details from the card service listen subject', () => {
        cardService.listen.subscribe((cardEvent) => {
          expect(cardEvent.card).toBe(mockCardResponse);
        });
      });
    });
  });
});

我现在要测试在对端点的下一个请求返回相同的卡响应时是否执行了正确的处理。

因此,在执行代码流传输之后,在检测到新的卡响应后将调用restartPoll,然后在1000毫秒后依次调用pollCardStatus。因此,我想用完全相同的卡响应刷新对端点的后续调用,以便可以点击handleCardStilPresentEvent函数,并检查控制台日志是否已执行。

因此,在上面的测试基础上,我尝试了以下方法:

import { CardService } from './card.service';
import { TestBed, getTestBed, fakeAsync, tick } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

describe('CardService Tests:', () => {
  let cardService: CardService;
  let injector: TestBed;
  let httpMock: HttpTestingController;
  let req;

  const mockCardResponse = {
    'type': 'SOME_CARD',
    'uid': 'xxx-111-222-ZZZ'
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [CardService]
    });
    injector = getTestBed();
    cardService = injector.get(CardService);
    httpMock = injector.get(HttpTestingController);
  });

  afterEach(() => {
    httpMock.verify();
  });

  describe('when polling for card status changes', () => {
    beforeEach(() => {
      cardService.pollCardStatus();
      req = httpMock.expectOne('http://someendpoint:1234/card');
        expect(req.request.method).toBe('GET');
    });
    describe('and a new card is detected', () => {
      beforeEach(() => {
        req.flush(mockCardResponse);
      });
      it('should be able inspect the card details from the card service listen subject', () => {
        cardService.listen.subscribe((cardEvent) => {
          expect(cardEvent.card).toBe(mockCardResponse);
        });
      });
        describe('and the same card is detected on the next poll response', () => {
        beforeEach(() => {
          req = httpMock.expectOne('http://someendpoint:1234/card');
          expect(req.request.method).toBe('GET');
          req.flush(itsoCardResponse);
        });
        it('should log a message to say the same card is still present', ) => {
          expect(console.log).toHaveBeenCalledWith('Card still present');
        });
      });
    });
  });
});

对控制台日志的期望失败,表明它从未调用。关于基于计时器的代码的测试,我遇到过fakeAsynctick,所以我怀疑这是导致我失败的原因,有人可以给我一些正确的方法吗? ?

谢谢

0 个答案:

没有答案