我正在尝试测试angular2应用程序。我有一个登录表单,它使用一个observable将数据发送到后端:
doLogin() {
this.usersService.login(this.model)
.subscribe((data) => {
console.log("In observable: " + data.isSuccess);
if (!data.isSuccess) {
this.alerts.push({});
}
});
}
在测试中,我在服务函数中添加了一个间谍,它返回了observable,以便组件可以对它进行处理:
usersService.login.and.returnValue(Observable.of(
<LoginResponse>{
isSuccess: true
}));
当一切准备就绪后,我会在提交按钮上发送一个事件,触发组件中的doLogin功能:
submitButton.dispatchEvent(new Event("click"));
fixture.detectChanges();
它正常工作。不幸的是,当我检查是否在测试中调用了usersService.login时:
expect(usersService.login).toHaveBeenCalled();
我收到错误,因为observable没有完成,登录尚未被调用。
我应该如何确定,在观察到完成后我检查了我的间谍?
答案 0 :(得分:1)
我不知道你如何在组件上配置服务,但是当我覆盖从TestComponentBuilder
创建的组件的提供者时,它对我有用。
我们来看一个样本。我有一个返回字符串列表的服务:
import {Observable} from 'rxjs/Rx';
export class MyService {
getDogs() {
return Observable.of([ 's1', 's2', ... ]);
}
}
组件使用此服务在单击按钮时异步显示列表:
@Component({
selector: 'my-list',
providers: [MyService],
template: `
<ul><li *ngFor="#item of items">{{ item }}</li></ul>
<div id="test" (click)="test()">Test</div>
`
})
export class MyList implements OnInit {
items:Array<string>;
service:MyService;
constructor(private service:MyService) {
}
test() {
this.service.getDogs().subscribe(
(dogs) => {
this.items = dogs;
});
}
}
我想测试一下,当我点击“Test”按钮时,会调用组件的test
方法,并间接调用服务的getDogs
方法。
为此,我创建了一个直接实例化服务并使用TestComponentBuilder
加载组件的测试。在这种情况下,我需要在调用overrideProviders
之前调用createAsync
方法。通过这种方式,您将能够提供您的间谍服务以通知该呼叫。这是一个示例:
let service:MyService = new MyService();
beforeEach(() => {
spyOn(service, 'getDogs').and.returnValue(Observable.of(
['dog1', 'dog2', 'dog3']));
});
it('should test get dogs', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb.overrideProviders(MyList, [provide(MyService, { useValue: service })])
.createAsync(MyList).then((componentFixture: ComponentFixture) => {
const element = componentFixture.nativeElement;
componentFixture.detectChanges();
var clickButton = document.getElementById('test');
clickButton.dispatchEvent(new Event("click"));
expect(service.getDogs).toHaveBeenCalled();
});
}));
修改强>
由于事件是异步触发的,因此您可以考虑使用fakeAsync
。后者允许您完全控制何时处理异步处理,并将异步内容转换为同步处理。
您可以将测试处理包装到
中fakeAsync((): void => {
var clickButton = document.getElementById('test');
clickButton.dispatchEvent(new Event("click"));
expect(service.getDogs).toHaveBeenCalled();
});
有关详细信息,您可以查看以下问题: