具有 observables 和 promise 的方法的单元测试
Unit test for method with observables and promise
我有这个方法,我正在尝试为其编写单元测试。
目前的测试只是以正确的顺序调用 spyOn 方法。
handleSave() {
this.saving = true;
this.presenters.presentLoader({
message: "Uploading..."
});
this.loginService.loginToFirebase().subscribe(() => {
Promise.all(
this.credential.inputs.map((input) => this.putStorageItem(input))
)
.then((url) => {
this.presenters.dismissLoader();
this.presenters.presentAlert({
message: 'Successfully Uploaded Identification.',
buttons: ['Ok']
});
this.presenters.dismissModal(true);
this.saving = false
})
.catch((error) => {
this.presenters.dismissLoader();
this.presenters.presentAlert({
message: 'Something went wrong.'
});
this.saving = false
});
})
}
到目前为止,单元测试适用于 presentLoader 的初始调用,但随后的 dismissLoader(在 loginToFirebase 可观察对象中并且 Promise.all 不会被调用(至少在可观察对象和承诺解决之前不会)
在我每次模拟 putStorageItem 之前
component.putStorageItem = (item) => Promise.resolve(true);
在里面,我用这个模拟了 loginService。
{
provide: LoginService,
useValue: {
loginToFirebase: () => of(true)
}
},
我目前的测试
it("call handle save should do stuff", () => {
let presenters = TestBed.inject(PresentersService);
spyOn(presenters, 'presentLoader');
spyOn(presenters, 'dismissLoader');
spyOn(presenters, 'presentAlert');
spyOn(presenters, 'dismissModal');
component.handleSave();
expect(presenters.presentLoader).toHaveBeenCalled();
expect(presenters.dismissLoader).toHaveBeenCalled();
expect(presenters.presentAlert).toHaveBeenCalled();
expect(presenters.dismissModal).toHaveBeenCalled();
});
putStorageItem
putStorageItem(input) {
const fileExt = input.file.metadata.name.split('.').slice(-1);
const filepath = ${input.label}.${fileExt}`;
let task;
if(input.file.metadata.isBase64) {
task = this.fireStorage.ref(filepath).put(this.util.b64toBlob(input.file.img), {contentType:input.file.metadata.type, customMetadata:{originalName:input.file.metadata.name}});
} else {
task = this.fireStorage.ref(filepath).put(input.file.img, {contentType:input.file.metadata.type, customMetadata:{originalName:input.file.metadata.name}});
}
input.fileProgress = task.percentageChanges();
return task.then((snapshot) => {
console.log('One success:', input.file)
}).catch((error) => {
console.log('One failed:', input.file, error.message)
});
}
由于您正在使用 Observables
and/or promises
,您需要使用不同的技术进行测试。这些技巧是:
- Jasmine
的done
回调
async/await
和 fixture.whenStable()
共 Angular
waitForAsync
和 fixture.whenStable()
共 Angular
fakeAsync
和 tick
共 Angular
您也可以在 Angular 中阅读有关异步测试的更多信息。
我最喜欢的是 fakeAsync
和 tick
,我认为它可以在这种情况下帮助您。
// !! wrap the test in a `fakeAsync` so you have better control of promises
it("call handle save should do stuff", fakeAsync(() => {
let presenters = TestBed.inject(PresentersService);
spyOn(presenters, 'presentLoader');
spyOn(presenters, 'dismissLoader');
spyOn(presenters, 'presentAlert');
spyOn(presenters, 'dismissModal');
component.handleSave();
// !! Call tick() to tell the test that before running the
// statements below the tick,
// ensure the promises in the component code have resolved
// since the expect statements rely on them.
tick();
expect(presenters.presentLoader).toHaveBeenCalled();
expect(presenters.dismissLoader).toHaveBeenCalled();
expect(presenters.presentAlert).toHaveBeenCalled();
expect(presenters.dismissModal).toHaveBeenCalled();
}));
tick
也可用于确保可观察流的 subscribe
在继续之前已完成,但我主要将其用于承诺。
我有这个方法,我正在尝试为其编写单元测试。 目前的测试只是以正确的顺序调用 spyOn 方法。
handleSave() {
this.saving = true;
this.presenters.presentLoader({
message: "Uploading..."
});
this.loginService.loginToFirebase().subscribe(() => {
Promise.all(
this.credential.inputs.map((input) => this.putStorageItem(input))
)
.then((url) => {
this.presenters.dismissLoader();
this.presenters.presentAlert({
message: 'Successfully Uploaded Identification.',
buttons: ['Ok']
});
this.presenters.dismissModal(true);
this.saving = false
})
.catch((error) => {
this.presenters.dismissLoader();
this.presenters.presentAlert({
message: 'Something went wrong.'
});
this.saving = false
});
})
}
到目前为止,单元测试适用于 presentLoader 的初始调用,但随后的 dismissLoader(在 loginToFirebase 可观察对象中并且 Promise.all 不会被调用(至少在可观察对象和承诺解决之前不会)
在我每次模拟 putStorageItem 之前
component.putStorageItem = (item) => Promise.resolve(true);
在里面,我用这个模拟了 loginService。
{
provide: LoginService,
useValue: {
loginToFirebase: () => of(true)
}
},
我目前的测试
it("call handle save should do stuff", () => {
let presenters = TestBed.inject(PresentersService);
spyOn(presenters, 'presentLoader');
spyOn(presenters, 'dismissLoader');
spyOn(presenters, 'presentAlert');
spyOn(presenters, 'dismissModal');
component.handleSave();
expect(presenters.presentLoader).toHaveBeenCalled();
expect(presenters.dismissLoader).toHaveBeenCalled();
expect(presenters.presentAlert).toHaveBeenCalled();
expect(presenters.dismissModal).toHaveBeenCalled();
});
putStorageItem
putStorageItem(input) {
const fileExt = input.file.metadata.name.split('.').slice(-1);
const filepath = ${input.label}.${fileExt}`;
let task;
if(input.file.metadata.isBase64) {
task = this.fireStorage.ref(filepath).put(this.util.b64toBlob(input.file.img), {contentType:input.file.metadata.type, customMetadata:{originalName:input.file.metadata.name}});
} else {
task = this.fireStorage.ref(filepath).put(input.file.img, {contentType:input.file.metadata.type, customMetadata:{originalName:input.file.metadata.name}});
}
input.fileProgress = task.percentageChanges();
return task.then((snapshot) => {
console.log('One success:', input.file)
}).catch((error) => {
console.log('One failed:', input.file, error.message)
});
}
由于您正在使用 Observables
and/or promises
,您需要使用不同的技术进行测试。这些技巧是:
- Jasmine 的
async/await
和fixture.whenStable()
共 AngularwaitForAsync
和fixture.whenStable()
共 AngularfakeAsync
和tick
共 Angular
done
回调
您也可以在 Angular 中阅读有关异步测试的更多信息。
我最喜欢的是 fakeAsync
和 tick
,我认为它可以在这种情况下帮助您。
// !! wrap the test in a `fakeAsync` so you have better control of promises
it("call handle save should do stuff", fakeAsync(() => {
let presenters = TestBed.inject(PresentersService);
spyOn(presenters, 'presentLoader');
spyOn(presenters, 'dismissLoader');
spyOn(presenters, 'presentAlert');
spyOn(presenters, 'dismissModal');
component.handleSave();
// !! Call tick() to tell the test that before running the
// statements below the tick,
// ensure the promises in the component code have resolved
// since the expect statements rely on them.
tick();
expect(presenters.presentLoader).toHaveBeenCalled();
expect(presenters.dismissLoader).toHaveBeenCalled();
expect(presenters.presentAlert).toHaveBeenCalled();
expect(presenters.dismissModal).toHaveBeenCalled();
}));
tick
也可用于确保可观察流的 subscribe
在继续之前已完成,但我主要将其用于承诺。