[英]Unit test fails when stream/event has pipe(takeUntil(destroy))
Angular:9.1.13; RxJS:6.6.3; 業力:4.3.0; 茉莉花核:2.6.2
我們有一個具有服務的組件,它對流和事件做一些事情。
每個這樣的組件方法在通過調用this._destroy.next()
被銷毀時取消訂閱流/事件,在ngOnDestroy
鈎子中聲明為private _destroy = new Subject()
的主題。
在我們運行單元測試之前,一切似乎都很好。 方法和測試示例可以在下面找到。
目前尚不清楚為什么在使用takeUntil
訂閱服務流/事件時測試失敗。
(另一個用例)不使用返回具有pipe(takeUntil(destroy))
使用 jasmine/karma 和 phantom.js 運行測試時出錯
TypeError: undefined is not a constructor (evaluating 'this.service.getServicePackages().pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_9__["takeUntil"])(this._destroy))')
方法示例:
getServicePackages(): void {
this.service.getServicePackages().pipe(takeUntil(this._destroy)).subscribe(() => ... );
}
測試示例:
beforeAll(() => {
serviceStub = {
getServicePackages: () => ({ subscribe: () => ({}) }),
// v2 -> getServicePackages: () => ({ subscribe: (): Observable<TYPE> => of({}) }),
}
})
it('...', () => {
const serviceStub = TestBed.inject(PackageService);
spyOn(serviceStub, 'getServicePackage').and.callThrough();
spyOn(component, 'getServicePackage').and.callThrough();
component.getServicePackage();
expect(component.getServicePackage).toHaveBeenCalled();
expect(serviceStub.getServicePackage).toHaveBeenCalled();
})
如果我們將 2 行放在一起,問題就會變得很明顯
serviceStub = {
getServicePackages: () => ({ subscribe: () => ({}) }),
// v2 -> getServicePackages: () => ({ subscribe: (): Observable<TYPE> => of({}) }),
};
// and then in code of component
serviceStub.getServicePackages().pipe(does not matter what); // here it doesn't have pipe method
我建議返回 observable 本身。 如果您還想測試事件 - 返回一個主題。
servicePackagesSubject = new Subject();
serviceStub = {
getServicePackages: jasmine.createSpy('getServicePackages').and.returnValue(servicePackagesSubject),
}
我認為這是推進此類案件的最佳方式:
// As mentioned earlier by @Andrei, it does not matter about the pipe operators.
// In your test case, create a mock service, return a value, and use it as a useClass method in the providers and simply spyOn your component method. Something like this:
// In your spec file,
@Injectable()
class MockService extends YourOriginalService {
getServicePackages() {
// Since you are subscribing, i am assuming this returns an observable, hence
// the 'of' operator
const mockData = {fill your mockData here};
return of(mockData);
}
}
// In your before each, add the mockService to your providers
let mockService: YourOriginalService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [],
....
providers: [
{
provide: YourOriginalService,
useClass: MockService
}
]
......
}).compileComponents();
mockService = TestBed.get(YourOriginalService);
}));
/// Now your test case turns to this:
it('should call the #getServicePackages() method in component', () => {
spyOn(component, 'getServicePackages').and.callThrough();
component.getServicePackages();
expect(component.getServicePackages).toHaveBeenCalled();
});
// Now if you want to test the 'error' part in the subscribe, you can take care of that in this test case like this:
it('should call the #getServicePackages() method in component, for error scenario', () => {
// Assuming its an API Call, otherwise replace the status object with your mock error object
spyOn(component, 'getServicePackages').and.callThrough();
spyOn(mockService, 'getServicePackages')
.and.returnValue(throwError(of({status: 500})));
component.getServicePackages();
expect(component.getServicePackages).toHaveBeenCalled();
});
// Note: Please don't mix the service success scenario coverage and service error scenario coverage in the same test case. Use 2 test cases like above.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.