Angular 2+,异步测试和 setTimeout

Posted

技术标签:

【中文标题】Angular 2+,异步测试和 setTimeout【英文标题】:Angular 2+, async testing and setTimeout 【发布时间】:2018-12-03 07:50:20 【问题描述】:

我有一个关于测试的问题。 我使用 Angular 6、karma 和 jasmine。

我的测试是:

it(`my test`, async(() => 
    console.log('### start test');
    fixture.detectChanges();
    // call a method which has async code
    fixture.componentInstance.fakeTimeout();
    console.log('isStable', fixture.isStable());
    fixture.whenStable().then(() => 
        // here I must check smth only when all async operations are completed
        console.log('### end test');
    );
));

我尝试以不同的方式实现fakeTimeout 方法,即:

public fakeTimeout() 
    new Promise((resolve, reject) => 
        setTimeout(() => 
            console.log('>>>>>> COMPONENT TIMEOUT!!!');
            resolve(true);
        , 2000);
    ).then(() => );

public fakeTimeout() 
    setTimeout(() => 
        console.log('>>>>>> COMPONENT TIMEOUT!!!');
    , 2000);

在这两种情况下,我都有以下日志:

### start test
isStable true
### end test
>>>>>> COMPONENT TIMEOUT!!!

但是,根据官方文档,whenStable promise 只有在所有异步操作完成后才会解析,并且日志必须是:

### start test
isStable true
>>>>>> COMPONENT TIMEOUT!!!
### end test

我做错了什么?如果我必须等待对组件的所有异步操作完成,我应该如何正确编写异步测试?

【问题讨论】:

【参考方案1】:

不确定,为什么fixture.whenStable() 不自己等待delay (setTimeout)

但正常的PromiseObservable 返回效果很好

但是你可以用任何一种方式解决它:

方法一:你可以使用tick()手动等待fakeAync

it(`my test`, fakeAsync(() => 
    console.log('### start test');
    fixture.detectChanges();
    // call a method which has async code
    fixture.componentInstance.fakeTimeout();
    tick(2100); // just more than the delay mentioned inside the component.
    console.log('isStable', fixture.isStable());
    fixture.whenStable().then(() => 
        // here I must check smth only when all async operations are completed
        console.log('### end test');
    );
));

方法2:在spec文件中拥有自己的setTimeout,使用done()完成测试

it(`my test`, ((done) => 
        console.log('### start test');
        fixture.detectChanges();
        // call a method which has async code
        fixture.componentInstance.fakeTimeout();
        setTimeout(()=> 
          console.log('isStable', fixture.isStable());
          console.log('### end test');
          done();
        ,2100)
));

【讨论】:

以上是关于Angular 2+,异步测试和 setTimeout的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2调用多个异步方法

Angular 11:对 HttpInterceptor 进行单元测试 - 异步计时器或 AfterAll 错误

异步需要 AsyncTestZoneSpec - Angular

Jasmine 2.0 async done() 和 angular-mocks inject() 在同一个测试 it()

JavaScript异步机制

es6之promise简单理解及使用