[英]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年。
这个问题应该足够普遍,以获得标准答案。
我在Angular2和Jasmine的上下文中提问 ,但是,我也对简单的“单元测试”方法感兴趣,例如当前测试完全独立于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.