Angular单元测试:含服务Observable订阅的@Input组件报流未定义错误
错误原因
核心原因是你Mock的Service没有正确模拟servicePropertyObs getter属性的返回值,Input setter触发时调用this.service.servicePropertyObs拿到了undefined,传入combineLatest后就会触发该报错。
你现有组件代码还存在几个隐性bug,也会导致运行/测试出错:
- Input setter的参数名为value,但判断条件写的是
if (v),运行时会报v未定义 - 组件内
_componentProp初始化漏了new关键字,本身就会是undefined - setter内直接订阅combineLatest,每次Input赋值都会生成新的订阅,没有销毁逻辑会导致内存泄漏,建议提前声明订阅对象或者用takeUntil绑定销毁流,每次set新值前先取消旧订阅。
单元测试编写方案
1. 构造正确的Service Mock
需要完整模拟Service被调用的属性,返回合法的Observable,这里用BehaviorSubject可以方便测试时主动修改发射值,覆盖不同场景。
2. 完整测试代码示例
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyComponent } from './my.component'; import { Service } from './你的Service实际路径'; import { BehaviorSubject } from 'rxjs'; // 替换为你实际Input入参的V类型 type V = Record<string, any>; describe('MyComponent', () => { let component: MyComponent; let fixture: ComponentFixture<MyComponent>; // 声明服务的模拟Subject,方便测试时主动发射值 let mockServiceSub: BehaviorSubject<number[]>; beforeEach(async () => { mockServiceSub = new BehaviorSubject<number[]>([1]); await TestBed.configureTestingModule({ declarations: [ MyComponent ], providers: [ { provide: Service, // jasmine.createSpyObj第三个参数用来模拟getter/setter属性 useValue: jasmine.createSpyObj('Service', [], { servicePropertyObs: mockServiceSub.asObservable() }) } ] }).compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('Input赋值后sum计算逻辑正确', () => { // 先给组件自身的componentProp发射测试值 (component as any)._componentProp.next([2]); // 给Input赋值触发setter逻辑 component.myInput = {} as V; // 修改服务发射的值,验证响应逻辑 mockServiceSub.next([3]); // 验证sum结果符合预期 3+2=5 expect(component.sum).toBe(5); }); });
3. 简化场景方案
如果你不需要测试服务值变更的联动逻辑,也可以直接将模拟的servicePropertyObs赋值为静态Observable,比如of([1])即可,只要保证返回的是合法的可迭代流就不会触发报错。
内容的提问来源于stack exchange,提问作者user253105
相关产品推荐
相关产品推荐

