Angular Jasmine单元测试报错:.subscribe is not a function问题求助
Angular单元测试:解决
getMakePaymentState$.subscribe is not a function报错 问题根源
你遇到的报错是因为**mockMakePaymentState对象中没有定义getMakePaymentState$方法**,直接用spyOn监听一个不存在的方法时,Jasmine无法正确创建该方法的间谍,导致组件调用this._payStateService.getMakePaymentState$()时,这个方法实际不存在,自然无法调用.subscribe()。
另外你的测试代码里还监听了getBankPayments,但这个方法同样没在mock对象里定义,后续也会触发类似问题,需要一起处理。
解决方案
步骤1:在Mock对象中预定义所有需要监听的方法
在mockMakePaymentState中添加getMakePaymentState$和getBankPayments的空实现,返回合法的Observable(因为组件会订阅这些方法的返回值):
let mockMakePaymentState = { getPaymentDetails$: () => of({} as IPaymentDetails), getDetails: () => {}, getUserInfo: () => {}, getMakePaymentState$: () => of({} as IPaymentDetails), // 新增方法,返回空Observable getBankPayments: () => of({} as PaymentBankDetails) // 新增方法,返回空Observable };
步骤2:修改测试用例中的间谍逻辑
现在可以正常用spyOn覆盖这些预定义方法的返回值:
it('should call ngOnInit', () => { spyOn(mockMakePaymentState, 'getDetails').and.returnValue(of(paymentInfoDetails)); spyOn(mockMakePaymentState, 'getBankPayments').and.returnValue(of(paymentBankDetails)); spyOn(mockMakePaymentState, 'getMakePaymentState$').and.returnValue(of(makePaymentState)); fixture.detectChanges(); });
注:
and.returnValue(of(...))比callFake更简洁,适合直接返回Observable的场景。
修改后的完整测试代码
fdescribe('DetailsComponent', () => { let component: DetailsComponent; let fixture: ComponentFixture<DetailsComponent>; let httpMock: HttpTestingController; let formModule: FormsModule; let form = new FormGroup({ username: new FormControl('', Validators.required), dob: new FormControl('') }); let mockbillingService = { getDetails: () => {}, getBankDetails: () => {} } let mockMakePaymentState = { getPaymentDetails$: () => of({} as IPaymentDetails), getDetails: () => {}, getUserInfo: () => {}, getMakePaymentState$: () => of({} as IPaymentDetails), // 新增 getBankPayments: () => of({} as PaymentBankDetails) // 新增 }; class MatDialogMock { open() { return { afterClosed: () => of({action: true}) }; } } let paymentInfoDetails = <PaymentInfoDetails>{}; let paymentBankDetails = <PaymentBankDetails>{}; let makePaymentState = <IPaymentDetails> {} paymentInfoDetails.banks = [paymentBankDetails]; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ ], imports: [ FormsModule, ReactiveFormsModule], providers: [ { provide: BillingService, useValue: mockbillingService }, {provide: PayState, useValue: mockMakePaymentState}, { provide: MatDialog, useClass: MatDialogMock } ] }) .compileComponents(); fixture = TestBed.createComponent(DetailsComponent); component = fixture.componentInstance; httpMock = TestBed.inject(HttpTestingController); formModule = TestBed.inject(FormsModule); }); it('should call ngOnInit', () => { spyOn(mockMakePaymentState, 'getDetails').and.returnValue(of(paymentInfoDetails)); spyOn(mockMakePaymentState, 'getBankPayments').and.returnValue(of(paymentBankDetails)); spyOn(mockMakePaymentState, 'getMakePaymentState$').and.returnValue(of(makePaymentState)); fixture.detectChanges(); }); });
内容的提问来源于stack exchange,提问作者user1015388
相关产品推荐
相关产品推荐

