it-swarm.com.de

Angular 2 fakeAsync wartet in einer Funktion mit tick () auf Timeout?

Ich versuche, die Ergebnisse aus einem nachgebildeten Backend in Angular 2 für Unit-Tests abzurufen. Derzeit verwenden wir fakeAsync mit einer Zeitüberschreitung, um den Zeitablauf zu simulieren.

aktueller Arbeitseinheitstest

it('timeout (fakeAsync/tick)', fakeAsync(() => {
    counter.getTimeout();
    tick(3000); //manually specify the waiting time
}));

Dies bedeutet jedoch, dass wir uns auf ein manuell definiertes Timeout beschränken. Nicht, wenn die asynchrone Aufgabe abgeschlossen ist. Ich versuche, tick() zu veranlassen, zu warten, bis die Aufgabe abgeschlossen ist, bevor ich mit dem Test fortfahre.

Dies scheint nicht wie beabsichtigt zu funktionieren.

Lesen Sie die fakeAsync und die tick und die Antwort hier erklärt Folgendes:

tick () simuliert den asynchronen Zeitablauf.

Ich habe ein plnkr-Beispiel erstellt das dieses Szenario simuliert.

Hier rufen wir die Methode getTimeout() auf, die eine interne asynchrone Task mit einer Zeitüberschreitung aufruft. Im Test versuchen wir, es zu verpacken und tick() aufzurufen, nachdem wir die Methode getTimeout() aufgerufen haben.

counter.ts

getTimeout() {
  setTimeout(() => {
    console.log('timeout')
  },3000)
}

counter.specs.ts

it('timeout (fakeAsync/tick)', fakeAsync(() => {
    counter.getTimeout();
    tick();
}));

Der Komponententest schlägt jedoch mit dem Fehler "Fehler: 1 Timer noch in der Warteschlange" fehl.

Hat das Problem hier im eckigen Repo irgendetwas damit zu tun?

Ist es möglich, mit tick() auf eine Timeout-Funktion zu warten? Oder gibt es einen anderen Ansatz, den ich verwenden kann?

6
nipuna777

Der Zweck von fakeAsync besteht darin, die Zeit innerhalb Ihrer Spezifikation zu steuern. tick wartet keine Zeit, da es sich um eine Synchronfunktion handelt, mit der der Zeitablauf simuliert wird. Wenn Sie warten möchten, bis die asynchrone Funktion abgeschlossen ist, müssen Sie async und whenStable verwenden. In Ihrem Beispiel dauert es jedoch 3 Sekunden, bis die Spezifikation gültig ist rate das nicht.

Der Grund, warum counter.spec.ts fehlschlägt, besteht darin, dass Sie nur den Ablauf von 0 Sekunden simuliert haben (normalerweise verwendet, um den nächsten Tick der Ereignisschleife darzustellen). Wenn also die Spezifikation abgeschlossen ist, sind immer noch verspottete Timer aktiv, und das scheitert an der gesamten Spezifikation. Es funktioniert tatsächlich einwandfrei, wenn Sie darüber informiert werden, dass eine Zeitüberschreitung verspottet wurde und nicht behandelt wird.

Grundsätzlich denke ich, dass Sie versuchen, fakeAsync und tick auf eine Weise zu verwenden, für die sie nicht vorgesehen waren. Wenn Sie ein Timeout auf die von Ihnen vorgeschlagene Weise testen müssen, ist es am einfachsten, die Funktion setTimeout selbst zu verspotten, sodass Sie unabhängig von der verwendeten Zeit einfach die Methode aufrufen können.

GEÄNDERT Ich bin auf ein verwandtes Problem gestoßen, bei dem ich die Timer löschen wollte, und da es sich nicht um das getestete Teil handelte, war es mir egal, wie lange es dauerte dauerte. Ich habe es versucht:

tick(Infinity);

Was geklappt hat, war aber supergeil. Am Ende ging ich mit

discardPeriodicTasks();

Und alle meine Timer wurden gelöscht.

10
nephiw

Versuche dies:

// I had to do this:
it('timeout (fakeAsync/tick)', (done) => {
  fixture.whenStable().then(() => {
       counter.getTimeout();
       tick();
    done();
  });
});

Quelle

1
SrAxi

Async

test.service.ts

export class TestService {
  getTimeout() {
    setTimeout(() => { console.log("test") }, 3000);
  }
}

test.service.spec.ts

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

describe("TestService", () => {
  let service: TestService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [TestService],
    });
  });

  it("timeout test", async(() => {
    service.getTimeout();
  });
});

Fake Async

test.service.ts

export class TestService {
  readonly WAIT_TIME = 3000;

  getTimeout() {
    setTimeout(() => { console.log("test") }, this.WAIT_TIME);
  }
}

test.service.spec.ts

import { TestBed, fakeAsync } from '@angular/core/testing';

describe("TestService", () => {
  let service: TestService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [TestService],
    });
  });

  it("timeout test", fakeAsync(() => {
    service.getTimeout();
    tick(service.WAIT_TIME + 10);
  });
});
0
christo8989

Am Ende jedes Tests füge hinzu:

 fixture.destroy();
 flush();
0
dangchithao

Normalerweise verwende ich die FlushMicrotasks-Methode in meinen Unit-Tests zur Verwendung mit meinen Diensten. Ich hatte gelesen, dass tick () FlushMicrotasks sehr ähnlich ist, aber auch die Jasmin-tick () -Methode nennt. 

0
Nick