如何对BehaviourSubject的.value属性进行单元测试?Angular报错解决
Angular单元测试报错:TypeError: Cannot read properties of undefined (reading 'value')
我是Angular新手,在写单元测试时遇到错误TypeError: Cannot read properties of undefined (reading 'value')。我的业务逻辑是:判断企业用户是否持有驾照,持有则把visible设为true,否则设为false。试过mock服务、返回假数据,但测试还是跑不通,代码如下:
hasLicense() { this.licenseService.getLicences( this.companyService.selectedCompany.value.companyId, this.companyService.selectedCompany.value.userId ).subscribe(l => { if(l.driver) { this.visible = true; } else { this.visible = false; } }); }
问题根源
报错核心是this.companyService.selectedCompany为undefined,直接访问其value属性导致空值异常。单元测试环境中未正确初始化该对象,导致方法执行时触发错误。
修复方案
1. 初始化CompanyService的selectedCompany
无论使用TestBed还是jest.mock,必须确保selectedCompany是一个包含value属性的对象(如果它是BehaviorSubject类型,需模拟为Observable)。
普通对象模拟(非Observable场景)
// 测试用例的beforeEach块中 const mockCompanyService = { selectedCompany: { value: { companyId: 'test-comp-id', userId: 'test-user-id' } } }; TestBed.configureTestingModule({ providers: [ { provide: CompanyService, useValue: mockCompanyService } ] });
BehaviorSubject模拟(Observable场景)
import { BehaviorSubject } from 'rxjs'; // 测试用例的beforeEach块中 const mockSelectedCompany = new BehaviorSubject({ companyId: 'test-comp-id', userId: 'test-user-id' }); const mockCompanyService = { selectedCompany: mockSelectedCompany }; TestBed.configureTestingModule({ providers: [ { provide: CompanyService, useValue: mockCompanyService } ] });
2. Mock LicenseService的getLicences方法
确保该方法返回可订阅的Observable,分别模拟“有驾照”和“无驾照”两种场景:
import { of } from 'rxjs'; // 测试用例的beforeEach块中 const mockLicenseService = jasmine.createSpyObj('LicenseService', ['getLicences']); // 按需切换模拟返回值 mockLicenseService.getLicences.and.returnValue(of({ driver: true })); // 有驾照 // mockLicenseService.getLicences.and.returnValue(of({ driver: false })); // 无驾照 TestBed.configureTestingModule({ providers: [ { provide: LicenseService, useValue: mockLicenseService } ] });
3. 编写完整测试用例
调用hasLicense()后,验证visible值是否符合预期,同时校验getLicences的调用参数:
it('当用户持有驾照时,visible应设为true', () => { const component = TestBed.inject(YourComponent); const licenseService = TestBed.inject(LicenseService) as jasmine.SpyObj<LicenseService>; const companyService = TestBed.inject(CompanyService); licenseService.getLicences.and.returnValue(of({ driver: true })); component.hasLicense(); expect(component.visible).toBe(true); expect(licenseService.getLicences).toHaveBeenCalledWith( companyService.selectedCompany.value.companyId, companyService.selectedCompany.value.userId ); }); it('当用户无驾照时,visible应设为false', () => { const component = TestBed.inject(YourComponent); const licenseService = TestBed.inject(LicenseService) as jasmine.SpyObj<LicenseService>; licenseService.getLicences.and.returnValue(of({ driver: false })); component.hasLicense(); expect(component.visible).toBe(false); });
4. 代码健壮性优化(可选)
在业务代码中添加空值保护,避免运行时也出现相同错误:
hasLicense() { const selectedCompany = this.companyService.selectedCompany?.value; if (!selectedCompany) { this.visible = false; return; } this.licenseService.getLicences(selectedCompany.companyId, selectedCompany.userId) .subscribe(l => { this.visible = !!l.driver; }); }
内容的提问来源于stack exchange,提问作者Zepler
相关产品推荐
相关产品推荐

