angular2 测试中 fakeAsync 的 tick() 和 done() 有啥区别?

Posted

技术标签:

【中文标题】angular2 测试中 fakeAsync 的 tick() 和 done() 有啥区别?【英文标题】:What is the difference between fakeAsync's tick() and done() in angular2 testing?angular2 测试中 fakeAsync 的 tick() 和 done() 有什么区别? 【发布时间】:2018-04-01 07:24:21 【问题描述】:

我正在尝试找出 fakeAsync 的 tick() 方法与 done() 的区别,正如一些 answers 在堆栈溢出时所建议的那样。

使用tick() 我们可以模拟超时,但是我们可以使用done() 来实现同样的效果吗?

为什么 Angular 认为 more viable method 而不是使用 asyncfakeAsync

举个例子。

这个方法对我有用...

it("Should display names",(done:any) => 
        component.names = [
            
                "firstname": "abc",
                "lastname": "max"
            ,
            
                "firstname": "def",
                "lastname": "max"
            ,
        ];
        done();
        fixture.detectChanges();
        let wrapBox = fixture.debugElement.queryAll(By.css('.wrapBox'));
        console.log(wrapBox);
);

但以下方法返回 '6 timer(s) still in queue' 错误...

it("Should display names",fakeAsync(() => 
        component.names = [
            
                "firstname": "abc",
                "lastname": "max"
            ,
            
                "firstname": "def",
                "lastname": "max"
            ,
        ];
        tick();
        fixture.detectChanges();
        let wrapBox = fixture.debugElement.queryAll(By.css('.wrapBox'));
        console.log(wrapBox);
));

注意

    数组 names 的数据是异步的,因为它是使用“get”操作从后端检索的。但在这里我是在嘲笑数据。

    数组中的数据被遍历并传递给另一个子组件,在视图中显示它。

【问题讨论】:

这篇文章很好理解blog.nrwl.io/… @AngularInDepth.com 感谢您的链接!值得一读! 【参考方案1】:

这两件事没有共同点。

done 只是一个回调,让您的测试运行器知道异步操作何时完成。

例如:

it('should wait for this promise to finish', done => 
  const p = new Promise((resolve, reject) =>
    setTimeout(() => resolve(`I'm the promise result`), 1000)
  );

  p.then(result => 
    // following will display "I'm the promise result" after 1s
    console.log(result);

    // this let your test runner know that it can move forward
    // because we're done here
    // the test will take 1s due to the setTimeout at 1000ms
    done();
  );
);

您也可以为此使用async(只是为了避免手动调用done):

it(
  'should wait for this promise to finish',
  async(() => 
    const p = new Promise((resolve, reject) =>
      setTimeout(() => resolve(`I'm the promise result`), 1000)
    );

    p.then(result =>
      // following will display "I'm the promise result" after 1s
      console.log(result)
    );

    // notice that we didn't call `done` here thanks to async
    // which created a special zone from zone.js
    // this test is now aware of pending async operation and will wait
    // for it before passing to the next one
  )
);

现在,fakeAsync 让您可以控制时间(这真的很强大),因此您可以以同步方式编写测试,并模拟时间流逝以避免等待 setTimeout,例如:

it(
  'should wait for this promise to finish',
  fakeAsync(() => 
    const p = new Promise((resolve, reject) =>
      setTimeout(() => resolve(`I'm the promise result`), 1000)
    );

    // simulates time moving forward and executing async tasks
    flush();

    p.then(result =>
      // following will display "I'm the promise result" **instantly**
      console.log(result)
    );

    // notice that we didn't call `done` here has there's no async task pending
  )
);

所以要明确一点,在上一个示例中使用 fakeAsync,如果 setTimeout 设置为 10 秒,测试仍会立即执行

【讨论】:

你也可以添加 done 是原生 Jasmine 方法,而 asyncfakeAsync 是由 Angular 测试框架添加的 确实,您只能通过从angular/core/testing 导入asyncfakeAsync 来使用它们:) @Maxime 很好的解释!谢谢! 这个故事中提到的 tick() 在哪里? Tick 与同花顺几乎相同。 Flush 将运行队列中的所有异步任务,如果没有提供参数,也会运行。但是你也可以决定以毫秒为单位消磨时间,它会运行那些只应该在这段时间内运行的任务。因此,例如,如果您必须设置超时,一个在 2 秒,另一个在 1,运行 tick(1000),只会调用第一个回调。【参考方案2】:

我做了一个小测试,帮助我了解 tick 可以做什么:

it('should tell me what tick can do...', fakeAsync(() => 
    let counter1 = 0;
    let counter2 = 0;
    let intervalTime = 1000;
    let passingTime = intervalTime*5;

    interval(intervalTime).subscribe(() => 
        counter1++;
    );

    setInterval(() => 
        counter2++;
    , intervalTime);

    expect(counter1).toBe(0);
    expect(counter2).toBe(0);

    let now = new Date().getTime();
    tick(passingTime);
    let later = new Date().getTime();

    expect(now).toBe(later-passingTime)

    expect(counter1).toBe(5);
    expect(counter2).toBe(5);

    discardPeriodicTasks();
));

【讨论】:

以上是关于angular2 测试中 fakeAsync 的 tick() 和 done() 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Angular2 NgModel 在 Jasmine 测试中没有获得价值

Angular 测试中的 fakeAsync 和 async 有啥区别?

为使用 Observables 的 Angular 2 组件编写 Jasmine 测试

角度测试中的 tick() 和 flush() 有啥区别?

Angular2 - 在测试中模拟 RouteParams

Angular2 - 在组件中测试 ngOninit