Angular Jasmine - 从组件中的模拟服务中侦测主题
Angular Jasmine - spy a subject from a mocked service in a component
您好,我正在测试一个组件,在该组件中我有两个主题的 CartService。我正在为该服务创建一个 spyObject。现在,当 angular 尝试订阅这些主题时,它们完全没有定义。试图 returnValue 的 Subject 或其他东西,但现在没有任何效果。仍未定义。
这是服务和主题。
export class CartService {
totalQuantity: Subject<number> = new Subject<number>();
totalPrice: Subject<number> = new Subject<number>();
}
然后在 ngOnInit() 的组件中我只是订阅了它们。这是 Angular 尝试订阅的地方,但它们未定义,我不知道如何模拟它们
this.subscribePrice = this.cartService.totalPrice.subscribe(data => this.totalPrice = data);
this.subscribeQuantity = this.cartService.totalQuantity.subscribe(data => this.totalQuantity = data);
这里是测试class:
fdescribe('CheckoutComponent', () => {
let component: CheckoutComponent;
let fixture: ComponentFixture<CheckoutComponent>;
let el: DebugElement;
let messageToastrService: any;
let cartService: any;
let priceSubject: Subject<number>;
let quantitySubject: Subject<number>;
beforeEach(async(() => {
priceSubject = new Subject<number>();
quantitySubject = new Subject<number>();
const messageToastrSpy = jasmine.createSpyObj('MessageToastrService', ['success']);
const cartServiceSpy = jasmine.createSpyObj('CartService',
['getCartFromStorage', 'computeTotals'], ['totalQuantity', 'totalPrice']);
TestBed.configureTestingModule({
declarations: [ CheckoutComponent ],
imports: [
ProductsModule,
RouterTestingModule.withRoutes([]),
HttpClientTestingModule,
],
providers: [
{provide: MessageToastrService, useValue: messageToastrSpy},
{provide: CartService, useValue: cartServiceSpy},
]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(CheckoutComponent);
component = fixture.componentInstance;
el = fixture.debugElement;
messageToastrService = TestBed.inject(MessageToastrService);
cartService = TestBed.inject(CartService);
fixture.detectChanges();
});
}));
现在只是专注于手头的事情。这些是我试图解决问题的方法。但是,仍然没有任何效果。
it('should properly initialize component', function() {
component.ngOnInit();
// cartService.totalPrice.and.returnValue(priceSubject.asObservable());
// cartService.totalQuantity.and.returnValue(quantitySubject.asObservable());
cartService.totalPrice.and.returnValue(of());
cartService.totalQuantity.and.returnValue(of());
// (cartService.totalPrice as jasmine.Spy).and.returnValue(priceSubject.asObservable());
// (cartService.totalQuantity as jasmine.Spy).and.returnValue(quantitySubject.asObservable());
});
踪迹:
Failed: Uncaught (in promise): TypeError: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
at CheckoutComponent.uploadCartInfo (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:62:55)
at CheckoutComponent.ngOnInit
error properties: Object({ rejection: TypeError: Cannot read property 'subscribe' of undefined, promise: [object Promise], zone: Zone({ _parent: Zone({ _parent: null, _name: '<root>', _properties: Object({ }), _zoneDelegate: ZoneDelegate({ _taskCounts: Object({ microTask: 0, macroTask: 0, eventTask: 0 }), zone: <circular reference: Object>, _parentDelegate: null, _forkZS: null, _forkDlgt: null, _forkCurrZone: null, _interceptZS: null, _interceptDlgt: null, _interceptCurrZone: null, _invokeZS: null, _invokeDlgt: null, _invokeCurrZone: null, _handleErrorZS: null, _handleErrorDlgt: null, _handleErrorCurrZone: null, _scheduleTaskZS: null, _scheduleTaskDlgt: null, _scheduleTaskCurrZone: null, _invokeTaskZS: null, _invokeTaskDlgt: null, _invokeTaskCurrZone: null, _cancelTaskZS: null, _cancelTaskDlgt: null, _cancelTaskCurrZone: null, _hasTaskZS: null, _hasTaskDlgt: null, _hasTaskDlgtOwner: null, _hasTaskCurrZone: null }) }), _name: 'ProxyZone', _properties: Object({ ProxyZoneSpec: ProxyZoneSpec({ defaultS ...
Error: Uncaught (in promise): TypeError: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
at CheckoutComponent.uploadCartInfo (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:62:55)
at CheckoutComponent.ngOnInit (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:40:10)
at callHook (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2922:1)
at callHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2892:1)
at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2844:1)
at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:7213:1)
at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:7312:1)
at tickRootContext (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8507:1)
at detectChangesInRootView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8532:1)
at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9918:1)
at resolvePromise (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:798:1)
at http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:864:1
at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:399:1)
at AsyncTestZoneSpec.onInvokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:1016:1)
at ProxyZoneSpec.onInvokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:320:1)
at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:398:1)
at Zone.runTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:167:1)
at drainMicroTaskQueue (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:569:1)
我该如何解决这个问题?谢谢。
在您的 CartService 中,totalQuantity 和 totalPrice 是主题。所以像这样嘲笑那些科目
cartService.totalQuantity.and.returnValue(new Subject<number>());
由于您在 ngOnInit 中访问这些主题,因此您必须在 CreateComponent 之前保留此间谍。所以把它放在 beforeEach 上面 create.
在 Szymon 的帮助下找到了答案。
首先我必须更改 cartServiceSpy 的 spyObject 并在下面添加这两个字段以监视它们。
const cartServiceSpy = jasmine.createSpyObj('CartService', ['getCartFromStorage', 'computeTotals']);
cartServiceSpy.totalQuantity = quantitySubject;
cartServiceSpy.totalPrice = priceSubject;
您好,我正在测试一个组件,在该组件中我有两个主题的 CartService。我正在为该服务创建一个 spyObject。现在,当 angular 尝试订阅这些主题时,它们完全没有定义。试图 returnValue 的 Subject 或其他东西,但现在没有任何效果。仍未定义。
这是服务和主题。
export class CartService {
totalQuantity: Subject<number> = new Subject<number>();
totalPrice: Subject<number> = new Subject<number>();
}
然后在 ngOnInit() 的组件中我只是订阅了它们。这是 Angular 尝试订阅的地方,但它们未定义,我不知道如何模拟它们
this.subscribePrice = this.cartService.totalPrice.subscribe(data => this.totalPrice = data);
this.subscribeQuantity = this.cartService.totalQuantity.subscribe(data => this.totalQuantity = data);
这里是测试class:
fdescribe('CheckoutComponent', () => {
let component: CheckoutComponent;
let fixture: ComponentFixture<CheckoutComponent>;
let el: DebugElement;
let messageToastrService: any;
let cartService: any;
let priceSubject: Subject<number>;
let quantitySubject: Subject<number>;
beforeEach(async(() => {
priceSubject = new Subject<number>();
quantitySubject = new Subject<number>();
const messageToastrSpy = jasmine.createSpyObj('MessageToastrService', ['success']);
const cartServiceSpy = jasmine.createSpyObj('CartService',
['getCartFromStorage', 'computeTotals'], ['totalQuantity', 'totalPrice']);
TestBed.configureTestingModule({
declarations: [ CheckoutComponent ],
imports: [
ProductsModule,
RouterTestingModule.withRoutes([]),
HttpClientTestingModule,
],
providers: [
{provide: MessageToastrService, useValue: messageToastrSpy},
{provide: CartService, useValue: cartServiceSpy},
]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(CheckoutComponent);
component = fixture.componentInstance;
el = fixture.debugElement;
messageToastrService = TestBed.inject(MessageToastrService);
cartService = TestBed.inject(CartService);
fixture.detectChanges();
});
}));
现在只是专注于手头的事情。这些是我试图解决问题的方法。但是,仍然没有任何效果。
it('should properly initialize component', function() {
component.ngOnInit();
// cartService.totalPrice.and.returnValue(priceSubject.asObservable());
// cartService.totalQuantity.and.returnValue(quantitySubject.asObservable());
cartService.totalPrice.and.returnValue(of());
cartService.totalQuantity.and.returnValue(of());
// (cartService.totalPrice as jasmine.Spy).and.returnValue(priceSubject.asObservable());
// (cartService.totalQuantity as jasmine.Spy).and.returnValue(quantitySubject.asObservable());
});
踪迹:
Failed: Uncaught (in promise): TypeError: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
at CheckoutComponent.uploadCartInfo (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:62:55)
at CheckoutComponent.ngOnInit
error properties: Object({ rejection: TypeError: Cannot read property 'subscribe' of undefined, promise: [object Promise], zone: Zone({ _parent: Zone({ _parent: null, _name: '<root>', _properties: Object({ }), _zoneDelegate: ZoneDelegate({ _taskCounts: Object({ microTask: 0, macroTask: 0, eventTask: 0 }), zone: <circular reference: Object>, _parentDelegate: null, _forkZS: null, _forkDlgt: null, _forkCurrZone: null, _interceptZS: null, _interceptDlgt: null, _interceptCurrZone: null, _invokeZS: null, _invokeDlgt: null, _invokeCurrZone: null, _handleErrorZS: null, _handleErrorDlgt: null, _handleErrorCurrZone: null, _scheduleTaskZS: null, _scheduleTaskDlgt: null, _scheduleTaskCurrZone: null, _invokeTaskZS: null, _invokeTaskDlgt: null, _invokeTaskCurrZone: null, _cancelTaskZS: null, _cancelTaskDlgt: null, _cancelTaskCurrZone: null, _hasTaskZS: null, _hasTaskDlgt: null, _hasTaskDlgtOwner: null, _hasTaskCurrZone: null }) }), _name: 'ProxyZone', _properties: Object({ ProxyZoneSpec: ProxyZoneSpec({ defaultS ...
Error: Uncaught (in promise): TypeError: Cannot read property 'subscribe' of undefined
TypeError: Cannot read property 'subscribe' of undefined
at CheckoutComponent.uploadCartInfo (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:62:55)
at CheckoutComponent.ngOnInit (http://localhost:9876/_karma_webpack_/webpack:/src/app/modules/products/components/checkout/checkout.component.ts:40:10)
at callHook (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2922:1)
at callHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2892:1)
at executeInitAndCheckHooks (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2844:1)
at refreshView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:7213:1)
at renderComponentOrTemplate (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:7312:1)
at tickRootContext (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8507:1)
at detectChangesInRootView (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:8532:1)
at RootViewRef.detectChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9918:1)
at resolvePromise (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:798:1)
at http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:864:1
at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:399:1)
at AsyncTestZoneSpec.onInvokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:1016:1)
at ProxyZoneSpec.onInvokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:320:1)
at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:398:1)
at Zone.runTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:167:1)
at drainMicroTaskQueue (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-evergreen.js:569:1)
我该如何解决这个问题?谢谢。
在您的 CartService 中,totalQuantity 和 totalPrice 是主题。所以像这样嘲笑那些科目
cartService.totalQuantity.and.returnValue(new Subject<number>());
由于您在 ngOnInit 中访问这些主题,因此您必须在 CreateComponent 之前保留此间谍。所以把它放在 beforeEach 上面 create.
在 Szymon 的帮助下找到了答案。
首先我必须更改 cartServiceSpy 的 spyObject 并在下面添加这两个字段以监视它们。
const cartServiceSpy = jasmine.createSpyObj('CartService', ['getCartFromStorage', 'computeTotals']);
cartServiceSpy.totalQuantity = quantitySubject;
cartServiceSpy.totalPrice = priceSubject;