我正在尝试测试Angular 4中组件的login()
方法,该方法依赖于返回成功或错误的Observable authService
:
受测试代码:
login() {
this.loginError = undefined;
this.loadingService.present('Logging In...');
this.authService
.login(this.form.value)
.subscribe(
(currentUser: any) => {
this.loadingService.dismiss();
this.navCtrl
.setRoot('TabsPage')
},
(error: any) => {
this.loadingService.dismiss();
this.loginError = error._body;
console.error('LoginPage :: Login Error:', error);
}
);
}
我知道要成功对此方法进行单元测试,我需要将其隔离。我为authService
创建了一个存根,并将其注入TestBed
:
身份验证存根
export class AuthenticationServiceStub {
login() {};
getCurrentUserFromStorage() {};
logout() {};
};
Testbed config:
TestBed.configureTestingModule({
declarations: [
...components,
],
providers: [
NavController,
LoadingService,
FormBuilder,
{ provide: AuthService, useClass: AuthenticationServiceStub }
],
imports: [
IonicModule.forRoot(LoginPage),
PierDataServicesModule.forRoot(),
],
});
据我所知,单元测试login()
我必须测试这4件事:
this.loginError
设置为undefined this.loadingService.present('Logging In...')
被称为this.authService.login(this.form.value)
被称为this.authService.login(this.form.value)
返回成功,那就是
成功功能块中的两个方法都被调用,如果是
错误,调用错误块中的方法。这就是我的规范,(我已经成功测试了1,2,3):
试验:
describe('Login()', () => {
let fixture: ComponentFixture<LoginPage>;
let instance: any = null;
let authService: any;
beforeEach(async(() => TestUtils.beforeEachCompiler([LoginPage]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
spyOn(instance, 'login').and.callThrough();
spyOn(instance.loadingService, 'present');
spyOn(instance.authService, 'login').and.returnValue({ subscribe: () => {} });
instance.login();
})));
it("should be callable", async(() => {
expect(instance.login).toHaveBeenCalled();
}));
it("should call loadingService.present ", async(() => {
expect(instance.loadingService.present).toHaveBeenCalled();
}));
it("should call authService.login", async() => {
expect(instance.authService.login).toHaveBeenCalled();
});
});
我无法弄清楚如何测试4号。如何通过成功或错误复制被调用的Observable,并检查这些函数体中的函数是否运行?
我可以构建模拟login()
方法并复制测试代码中的功能,但是测试模拟方法而不是实际代码似乎非常违反直觉。
我应该使用真正的authService
方法并构建一个模拟后端吗?这是有用的吗?如果是这样,怎么样?
我应该使用Karma spyOn
方法并修改它们来做我想要的吗?我想我可以做这样的事情:spyOn(instance.authService, 'login').and.callThrough().and.throwError()
但是这种方法没有成功。
答案 0 :(得分:1)
实际服务不应该参与单元测试,因为这会引入额外的移动部件。
测试promises和observables的一种简洁方法是提供一个真实的,而不是模仿它们的对象:
spyOn(instance.authService, 'login').and.returnValue(Observable.of(null));
...
expect(instance.loadingService.dismiss).toHaveBeenCalled();
expect(instance.navCtrl.setRoot).toHaveBeenCalledWith('TabsPage');
expect(instance.lognError).toBe(...);
...
const _body = {};
spyOn(instance.authService, 'login').and.returnValue(Observable.throw({ _body }));
...
expect(instance.loadingService.dismiss).toHaveBeenCalled();
expect(instance.navCtrl.setRoot).not.toHaveBeenCalled();
expect(instance.lognError).toBe(_body);