我有一个我要为其创建单元测试的应用程序。有一种特殊的方法,它通过可观察的管道和承诺的复杂链来创建一个可观察的对象,然后订阅所创建的可观察对象。我需要验证在订阅内部进行的方法调用。
结构是这样的:
private obs$: Observable<T>;
private subscription: Subscription;
methodToTest(): void {
this.obs$ = from( ... ).then( /* chain of piped observables */ );
this.subscription = this.obs$
.subscribe(
(value: T) => {
// bunch of logic
methodToBeVerifiedWasCalled();
},
(error) => { /* error handling */ }
);
}
到目前为止,我的测试如下:
it('the method to be verified is successfully called', () => {
// various mocking set up
this.mockApi.methodThatReturnsAPromise.and.returnvalue(Promise.resolve());
// etc.
this.classUnderTest.methodToTest();
// assertions for the various mocks...
expect(this.mockApi.methodThatReturnsAPromise).toHaveBeenCalled();
// etc.
// assert that the target method was called:
expect(this.classUnderTest.methodToBeVerifiedWasCalled).toHaveBeenCalled();
expect(this.classUnderTest.subscription).toBeDefined();
});
当然,该测试在最后的断言中失败,因为methodToBeVerifiedWasCalled
实际上是在订阅块内部调用的,并且该测试只是在同步地运行。 (在这里,classUnderTest
是一个间谍对象,其中有methodToBeVerifiedWasCalled
被监视。)
由于该方法为可观察对象分配了一个值,因此我不能仅在异步测试中订阅classUndertest.obs$
并验证返回的值(无论如何实际上并不能帮助解决问题。)如何验证subscribe块内部的方法是否被调用?
我不能更改源代码,只能更改测试。
答案 0 :(得分:1)
您需要使测试异步,然后在methodToTest()
之后等待。如果methodToTest()
没有返回您可以等待的承诺或可观察的结果,那么您将被迫等待一段时间。像这样:
function delay(ms) {
return new Promise(resolve => setTimeout(ms, resolve));
}
it('the method to be verified is successfully called', async (done) => {
// various mocking set up
this.mockApi.methodThatReturnsAPromise.and.returnvalue(Promise.resolve());
// etc.
const result = this.classUnderTest.methodToTest();
// if the method actually returned a promise you could: await result;
// since it does not, you can just await time:
await delay(1000); // wait 1 second
// assertions for the various mocks...
expect(this.mockApi.methodThatReturnsAPromise).toHaveBeenCalled();
// etc.
// assert that the target method was called:
expect(this.classUnderTest.methodToBeVerifiedWasCalled).toHaveBeenCalled();
expect(this.classUnderTest.subscription).toBeDefined();
// tell jasmine test is done
done();
});