【问题标题】:Angular 2 Observable testing Error: Cannot use setInterval from within an async zone testAngular 2 Observable 测试错误:无法在异步区域测试中使用 setInterval
【发布时间】:2017-03-07 15:42:16
【问题描述】:

我正在尝试测试一个组件,该组件使用进行异步 http 调用的服务。该服务返回一个 Observable,组件订阅该 Observable。

服务代码sn-p:

getRecentMachineTemperatures(_machine_Id): Observable<IDeviceReadings[]> {

    return this.http.get(TemperatureService.URL + _machine_Id)
      .map(response => { return response.json(); })
      .map((records: Array<any>) => {
        let result = new Array<IDeviceReadings>();
        if (records) {
          records.forEach((record) => {
            let device = new IDeviceReadings();
            device.device_id = record.device_id;

            if (record.d) {
              record.d.forEach((t) => {
                let temperature = new ITemperature();
                temperature.timestamp = t.timestamp;
                temperature.value = t.temperature;

                device.temperatures.push(temperature);
              });
            }

            result.push(device);
          });
        }
        return result;
      });
  }

组件代码sn-p:

  ngOnInit() {
    this.getRecentTemperatures();
  }

  getRecentTemperatures() {
    this.temperatureService.getRecentMachineTemperatures(this.machine_id)
      .subscribe(
        res => {
          let device1 = res[0];
          this.deviceId = device1.device_id;
          this.initTemperatures(device1.temperatures);
          this.updateChart();
        },
        error => console.log(error));
  }

我的测试设置依赖关系,监视服务“getRecentMachineTemperatures”并设置 i 返回一些存根数据。我一直在谷歌上搜索测试这个的方法,因此导致了 3 个不同的测试,试图测试同样的东西。每个都给我一个不同的错误。

温度.组件.spec.ts:

let machine_id = 1;
let comp:                 TemperatureComponent;
let fixture:              ComponentFixture<TemperatureComponent>;
let de:                   DebugElement;
let el:                   HTMLElement;
let temperatureService:   TemperatureService;
let stubDevices:          IDeviceReadings[];
let stubTemperatures:     ITemperature[];
let spyRecentTemps:       Function;

describe('Component: Temperature', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [TemperatureComponent],
      imports: [ ChartsModule ],
      providers: [
        MockBackend,
        BaseRequestOptions,
        { provide: Http,
          useFactory: (backend, defaultOptions) => {
            return new Http(backend, defaultOptions);
          },
          deps: [MockBackend, BaseRequestOptions]},
        TemperatureService
      ]
    });

    stubDevices = new Array<IDeviceReadings>();

    let stubDevice = new IDeviceReadings();
    stubDevice.device_id = 'stub device';
    stubDevice.temperatures = new Array<ITemperature>();

    let stubTemp = new ITemperature();
    stubTemp.timestamp = new Date().getTime();
    stubTemp.value = 10;

    stubDevice.temperatures.push(stubTemp);
    stubDevices.push(stubDevice);

    stubTemperatures = new Array<ITemperature>();

    let stubTemp2 = new ITemperature();
    stubTemp.timestamp = new Date().getTime() + 1;
    stubTemp.value = 11;

    stubTemperatures.push(stubTemp2);

    fixture = TestBed.createComponent(TemperatureComponent);
    comp = fixture.componentInstance;

    temperatureService = fixture.debugElement.injector.get(TemperatureService);

    spyRecentTemps = spyOn(temperatureService, 'getRecentMachineTemperatures')
      .and.returnValue(Observable.of(stubDevices).delay(1));

    //  get the "temperature-component" element by CSS selector (e.g., by class name)
    de = fixture.debugElement.query(By.css('.temperature-component'));
    el = de.nativeElement;
  });

  it('should show device readings after getRecentTemperatures subscribe (fakeAsync)', fakeAsync(() => {
    fixture.detectChanges();
    expect(spyRecentTemps.calls.any()).toBe(true, 'getRecentTemperatures called');

    tick(1000);
    fixture.detectChanges();
    expect(el.textContent).toContain(stubDevices[0].temperatures[0].timestamp);
    expect(el.textContent).toContain(stubDevices[0].temperatures[0].value);
  }));

  it('should show device readings after getRecentTemperatures subscribe (async)', async(() => {
      fixture.detectChanges();
      expect(spyRecentTemps.calls.any()).toBe(true, 'getRecentTemperatures called');

      fixture.whenStable().then(() => {
        fixture.detectChanges();
        expect(el.textContent).toContain(stubDevices[0].temperatures[0].timestamp);
        expect(el.textContent).toContain(stubDevices[0].temperatures[0].value);
      });
  }));

  it('should show device readings after getRecentTemperatures subscribe (async) (done)', (done) => {
    async(() => {
      fixture.detectChanges();
      expect(spyRecentTemps.calls.any()).toBe(true, 'getRecentTemperatures called');

      fixture.whenStable().then(() => {
        fixture.detectChanges();
        expect(el.textContent).toContain(stubDevices[0].temperatures[0].timestamp);
        expect(el.textContent).toContain(stubDevices[0].temperatures[0].value);
      }).then(done);
    });
  });
});

fakeAsync 失败并显示:“错误:1 个计时器仍在队列中。”

异步失败:“错误:无法在异步区域测试中使用 setInterval。”

异步(完成)失败:“错误:超时 - 在 jasmine.DEFAULT_TIMEOUT_INTERVAL 指定的超时内未调用异步回调。”

我将如何测试具有异步服务依赖项的组件?

据我了解,这可能是关于 Rx 库中的 AsyncScheduler 使用 Date().now 而不是伪造的时间 (https://github.com/angular/angular/issues/10127)。如果是这样,这是否已解决?或者有人找到了解决方法?

我正在使用 angular-cli: 1.0.0-beta.16。节点:4.4.2。 npm:3.10.6。 webpack 2.1.0-beta.22。

【问题讨论】:

  • 您是在代码中的某处调用setInterval,还是被某个未知的第三方调用?
  • 我认为 setInterval 是由 'Observable.of(stubDevices).delay(1)' 调用的
  • 调用它的目的是什么?您需要调用它吗?它只是在测试中被调用。也许你可以以某种方式解决这个问题。
  • 我需要调用它来模拟异步行为。如果我不监视函数立即返回并且测试不是异步的。
  • 不,我的意思是,有必要打电话给delay(因为这是问题所在)吗?

标签: unit-testing asynchronous angular typescript jasmine


【解决方案1】:

我有..

import 'rxjs/add/operator/timeout';

return this.http[method](url, emit, this.options)
    .timeout(Config.http.timeout, new Error('timeout'))

导致此错误的原因。我相信 RXJS .timeout 在后台调用 setInterval。

我通过切换解决了这个问题...

it('blah', async(() => {     

it('blah', (done) => {

【讨论】:

    猜你喜欢
    • 2016-11-29
    • 2017-05-25
    • 1970-01-01
    • 2017-08-17
    • 2018-12-03
    • 2021-06-14
    • 1970-01-01
    • 2018-05-17
    • 1970-01-01
    相关资源
    最近更新 更多