如何测试组件行为以响应promise

时间:2016-03-14 00:34:03

标签: typescript jasmine angular es6-promise

首先,我不相信它是重复的,因为SO问题和答案描述了angular1中的承诺处理测试,并通过调用$timeout.flush()$rootScope.$apply()来解决,因此不适用于此 Angular2 案例。

我的问题是如何测试解析promise 后正在执行的Angular2组件的逻辑。 (最好是Jasmine)。

为了说明这一点,我修改了Angular2文档中的快速入门示例。简单组件列出现有的英雄,并允许注册新的英雄。 heros列表和注册由一个服务完成,该服务将响应作为Promises(带有heros列表或新注册的hero对象)返回。

现在一旦注册了一个新英雄(并且Promise已解决),我希望该组件选择英雄并再次检索英雄列表:

...
register(heroName:string) {
  this.postRegistration(this._heroService.registerHero(heroName));
}
//this extra method helps testing without stubing of the service
postRegistration(heroPromise:Promise<Hero>) {
  heroPromise.then( hero => {
      //I want to test that the two actions below took place
      this.selectedHero = hero;
      this.getHeroes(); })
}

getHeroes() {
this._heroService.getHeroes().then(heroes => this.heroes = heroes);
}

我将注册拆分为两种方法,因此可以在不使用服务存根的情况下进行测试

使用Jasmine异步测试done()我可以轻松测试服务行为,即。它会返回正确的承诺。 但是如何测试,组件调用getHeros来刷新其列表或正确设置所选英雄。

我设法测试使用spec设置变量:

it("postRegistration sets selectedHero as registered one",done =>{
    let promise = service.registerHero("Bosek"); //Promise.resolve(hero);
    component.postRegistration(promise);
    promise.then( hero => {
        expect(component.selectedHero).toBe(hero);
        expect(component.heroes.indexOf(hero)).toBeGreaterThan(0);
        done();
    })
}) 

我&#34;迷上了#34;我断言传递给组件的同一个承诺。

我的第一个问题:我是幸运的,还是保证,如果我订阅同一个承诺并致电其“&#39;那么&#39;条款jasmine done()它会等到我的其他&#34;订阅者&#34; (在那种情况下是组件)承诺和后续过程。

其次,有没有办法强制所有Promise在测试期间保持同步,这样才能解决整个问题。

我找到了模拟承诺项目https://github.com/charleshansen/mock-promises,它允许&#34;解雇&#34;承诺,但它已经死了2年。

这个问题应该足够常见才能得到标准答案。

我在 Angular2 Jasmine 的背景下提问,但是,我对简单的单元测试&#39;感兴趣。方法,例如当前测试完全独立于Angular框架。因为我不能正常使用JS,所以请打字。

整个代码(它是Angular2 Hero快速启动示例的简单克隆)位于:https://github.com/tzielins/angular-start-project

2 个答案:

答案 0 :(得分:2)

@Gunter回答让我走上正轨,但由于他没有明确解决问题,我正在写自己的答案。

  

我的第一个问题

我确实很幸运。随后调用相同的承诺,对之前的承诺没有任何影响。虽然这个测试通过了,但其他类似模式的测试失败了。

从商业中回复承诺&#34;方法和链接,并不总是一个选项,因为它取决于方法逻辑,所以Gunter的建议并不总是可以遵循。

  

其次

Gunter提到了Angular2 fakeAsync,它是测试Promise处理副作用的正确方法。虽然它是angular2测试库的一部分,但它可以用于单元测试&#39;方式,因为它不需要注入或其他角度依赖。

使用它,在flushMicrotasks体内调用fakeAsync并测试副作用:

import {it,fakeAsync,tick,flushMicrotasks} from 'angular2/testing';
...
    it('correct side effect after processing promise',<any>fakeAsync(()  => {

        let p = Promise.resolve(X);

        //invoking business logic
        component.dealWithIt(p);

        flushMicrotasks();

        //now the side effects can be tested in synchronous way
        expect(component.selectedHero).toBe(hero);
        ...
    }));

tick()对承诺也有类似的效果。

即使是在业务方法中创建的新承诺也能保证完成。我在这里问了一下:Does fakeAsync guarantee promise completion after tick/flushMicroservice我也发现了确认它的Angular测试规范。

答案 1 :(得分:1)

  

我的第一个问题:

你应该始终确保返回承诺

register(heroName:string) {
  return this.postRegistration(this._heroService.registerHero(heroName));
}
//this extra method helps testing without stubing of the service
postRegistration(heroPromise:Promise<Hero>) {
  return heroPromise.then( hero => {
      //I want to test that the two actions below took place
      this.selectedHero = hero;
      return this.getHeroes(); })
}

getHeroes() {
  return this._heroService.getHeroes().then(heroes => this.heroes = heroes);
}

这样,当您在返回值上调用.then(...)时,异步部分会被链接,否则异步调用将成为他们自己断开连接的事件链,并且您无法获得有关何时执行或何时执行的任何信息他们已经完成了。

  

其次

有一个fakeAsync应允许用于测试Angular2 testing with fakeAsync (我自己没试过)

否则承诺是异步的,没有什么可以改变它。