web-dev-qa-db-ja.com

Angular 2 tick()を使用する関数でタイムアウトを待つfakeAsync?

Angular 2の単体テスト用にモックバックエンドから結果を取得しようとしています。現在、タイムアウトのfakeAsyncを使用して、時間の経過をシミュレートしています。

現在の作業単位テスト

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

ただし、これは、手動で定義されたタイムアウトに制限されることを意味します。非同期タスクが完了したときではありません。私がやろうとしているのは、テストを続行する前に、タスクが完了するまでtick()を待機させることです。

これは意図したとおりに機能しないようです。

fakeAsynctickの答え ここ を読んで説明します:

tick()は非同期の時間経過をシミュレートします。

このシナリオをシミュレートする plnkrの例 を設定しました。

ここでは、タイムアウトを持つ内部非同期タスクを呼び出すgetTimeout()メソッドを呼び出します。テストでは、tick()メソッドを呼び出した後、ラップしてgetTimeout()を呼び出します。

counter.ts

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

counter.specs.ts

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

ただし、ユニットテストは「エラー:1個のタイマーがまだキューに残っています」というエラーで失敗します。

angular repo の問題は、これと何か関係がありますか?

この方法でtick()を使用してタイムアウト関数を待つことは可能ですか?または、私が使用できる別のアプローチはありますか?

15
nipuna777

fakeAsyncの目的は、仕様内で時間を制御することです。 tickは時間の経過をシミュレートするために使用される同期関数であるため、時間を待機しません。非同期関数が完了するまで待機する場合は、asyncおよびwhenStableを使用する必要がありますが、この例では、仕様の合格に3秒かかるため、これはお勧めしません。

counter.spec.tsが失敗する理由は、0秒の経過のみをシミュレートしたためです(通常はイベントループの次のティックを表すために使用されます)。そのため、仕様が完了すると、まだモックされたタイマーがアクティブになり、仕様全体が失敗します。タイムアウトがモックされ、処理されていないことを通知することで、実際に適切に動作しています。

基本的に、あなたはfakeAsynctickを使用するつもりのない方法で使用しようとしていると思います。提案した方法でタイムアウトをテストする必要がある場合、最も簡単な方法はsetTimeout関数をモックして、使用する時間に関係なくメソッドを呼び出すことです。

[〜#〜] edited [〜#〜]タイマーをクリアしたいという関連問題に遭遇しました。これはテスト中の部分ではなかったので、どのくらい長く気にしませんでした取った。私は試した:

tick(Infinity);

これは機能しましたが、非常にハッキーでした。私はで行きました

discardPeriodicTasks();

そして、私のタイマーはすべてクリアされました。

10
nephiw

各テストの最後に次を追加します。

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

これを試して:

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

ソース

1
SrAxi

非同期

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();
  });
});

偽の非同期

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

私は通常、サービスで使用するユニットテストでflushMicrotasksメソッドを使用します。 tick()はflushMicrotasksに非常に似ているが、jasmine tick()メソッドも呼び出すことを読みました。

0
Nick