我目前正在为我的一个组件编写单元测试。特别是,我有login(): void
功能。这是简化的逻辑:
login(): void {
this.showSpinner = true;
this.userService.login(loginData)
.subscribe(result => {
this.showSpinner = false;
}
)
}
我正在努力编写一个测试,在调用showSpinner
之前检查true
属性是否设置为userService.login
。
这是我的测试:
it('should display the spinner when the form is being saved',
inject([TestComponentBuilder], fakeAsync((tcb: any) => {
createComponent(tcb).then((fixture:ComponentFixture<any>) => {
fixture.componentInstance.login();
expect(fixture.componentInstance.showSpinner).toBe(true);
tick();
});
})));
});
此测试失败,因为.subscribe
立即解析/运行(我尝试在我的组件中注释掉this.showSpinner = false
,并且测试已通过)。
在我的userService
模拟中,对于login
方法模拟,我有以下内容:
this.loginSpy = this.spy('login').andReturn(Observable.of(this));
this
为mockUserService
的位置。
我确信我正在嘲笑userService
,特别是login
上userService
方法,因为我对此组件的其他测试行为正确。
我还尝试从我的间谍返回Observable.of(this).delay(1)
,然后在我的测试中调用tick(1)
。然而,这导致行为不一致,有时我的测试通过,但有时我得到一个错误说:
Error: 1 periodic timer(s) still in the queue.
如何测试.subscribe()
之前的逻辑?
答案 0 :(得分:0)
经过更多的考虑后,我意识到我目前的代码并不遵守单一责任原则。这个想法来自于每个人都在重复你应该“重构难以测试代码”的事实。
考虑到这一点,我已经将调用userService.login
之前需要完成的所有逻辑移动到它自己的单独函数中。这基本上导致:
login():void {
this.userService.login(this.loginData)
.subscribe(result => {
this.showSpinner = false;
});
}
formSubmit(): void {
this.showSpinner = true;
this.login();
}
这个逻辑现在更容易测试。
HOWEVER 我们需要记得在我们测试login()
时在我们的formSubmit()
方法上添加一个间谍,就像我们没有,formSubmit()
一样只需拨打login()
,这将再次同步完成,我们将遇到同样的问题。所以我对此功能的最新测试是:
it('should display the spinner when the form is being saved',
inject([TestComponentBuilder], fakeAsync((tcb: any) => {
createComponent(tcb).then((fixture:ComponentFixture<any>) => {
var loginSpy = spyOn(fixture.componentInstance, 'login');
fixture.componentInstance.formSubmit();
expect(fixture.componentInstance.showSpinner).toBe(true);
});
})));
});