繁体   English   中英

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

[英]How to test component behaviour in response to promise

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

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

为了说明这一点,我修改了Angular2文档中的快速入门示例。 简单组件列出现有的英雄,并允许注册新的英雄。 英雄列表和注册由服务完成,该服务将响应作为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);
}

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

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

我设法测试用规范设置变量:

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

我将我的断言“挂钩”到传递给组件的同一个承诺。

我的第一个问题 :我是幸运还是保证如果我订阅相同的承诺并从其'then'子句调用jasmine done(),它将等到我的其他“订阅者”(在这种情况下组件)处理该承诺和后续的。

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

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

这个问题应该足够普遍,以获得标准答案。

我在Angular2Jasmine的上下文中提问 ,但是,我也对简单的“单元测试”方法感兴趣,例如当前测试完全独立于Angular框架。 请打字,因为我通常不使用JS。

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

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

我的第一个问题

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

从“商业”方法返回承诺并链接到它,并不总是一个选项,因为它取决于方法逻辑,因此Gunter建议并不总是可以遵循。

其次

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

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

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()对promises有类似的影响。

即使是在业务方法中创建的新承诺也能保证完成。 我在这里问过: fakeAsync保证在tick / flushMicroservice之后完成承诺 ,我还发现了确认它的Angular测试规范。

我的第一个问题:

你应该始终确保退还承诺

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应该允许使用fakeAsync测试Angular2测试 (我自己没试过)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM