Angular单元测试:如何编写Subscribe及响应的测试用例并解决覆盖率问题
Angular单元测试覆盖
fetchControlDetailById全分支方案 你的代码存在两个关键分支需要覆盖:res.controlPresent为true和false的情况,分别对应showPortiqueEssaiBool设为false和true的逻辑。以下是具体的测试用例编写步骤和代码:
测试前置准备
在组件测试文件中,先mockControlService(假设服务类名为ControlService),用Jasmine的createSpyObj创建模拟对象,并在TestBed配置中注入:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; import { YourComponent } from './your-component.component'; import { ControlService } from './control.service'; describe('YourComponent', () => { let component: YourComponent; let fixture: ComponentFixture<YourComponent>; let mockControlService: jasmine.SpyObj<ControlService>; beforeEach(async () => { // 创建mock服务,包含fetchControlDetailById方法 mockControlService = jasmine.createSpyObj('ControlService', ['fetchControlDetailById']); await TestBed.configureTestingModule({ declarations: [YourComponent], providers: [ { provide: ControlService, useValue: mockControlService } ] }).compileComponents(); fixture = TestBed.createComponent(YourComponent); component = fixture.componentInstance; }); // 测试用例写在这里 });
测试用例1:当controlPresent为true时
覆盖if (res.controlPresent)为真的分支,验证所有属性赋值和视图控制逻辑:
it('should update properties and hide dropdown when controlPresent is true', () => { // 构造测试用响应数据 const testControlName = 'test-control'; const mockResponse = { controlPresent: true, portiqueList: ['port1', 'port2'], controlTest: 'test-data', controlHistoryDto: 'history-data' }; // 让mock服务返回响应的Observable mockControlService.fetchControlDetailById.and.returnValue(of(mockResponse)); // 调用组件方法 component.fetchControlDetailById(testControlName); // 断言服务方法调用正确性 expect(mockControlService.fetchControlDetailById).toHaveBeenCalledWith(testControlName); // 断言组件属性赋值正确性 expect(component.controlDetails).toEqual(mockResponse); expect(component.portiqueArr).toEqual(mockResponse.portiqueList); expect(component.controlTest).toEqual(mockResponse.controlTest); expect(component.controlPresentBool).toBeTrue(); expect(component.testSource).toEqual(mockResponse.controlHistoryDto); expect(component.showPortiqueEssaiBool).toBeFalse(); });
测试用例2:当controlPresent为false时
覆盖if (res.controlPresent)为假的分支,验证showPortiqueEssaiBool保持为true:
it('should update properties and show dropdown when controlPresent is false', () => { const testControlName = 'test-control-2'; const mockResponse = { controlPresent: false, portiqueList: ['port3', 'port4'], controlTest: 'test-data-2', controlHistoryDto: 'history-data-2' }; mockControlService.fetchControlDetailById.and.returnValue(of(mockResponse)); component.fetchControlDetailById(testControlName); expect(mockControlService.fetchControlDetailById).toHaveBeenCalledWith(testControlName); expect(component.controlDetails).toEqual(mockResponse); expect(component.portiqueArr).toEqual(mockResponse.portiqueList); expect(component.controlTest).toEqual(mockResponse.controlTest); expect(component.controlPresentBool).toBeFalse(); expect(component.testSource).toEqual(mockResponse.controlHistoryDto); expect(component.showPortiqueEssaiBool).toBeTrue(); });
补充说明
- 确保mock数据包含所有响应字段,避免属性赋值时出现未定义的情况
- 若组件依赖变更检测更新视图,可在调用方法后添加
fixture.detectChanges()(直接赋值组件属性的场景一般无需额外触发) - 运行测试后,代码覆盖率将覆盖
next回调内的所有逻辑,包括if分支的两种情况
内容的提问来源于stack exchange,提问作者Ajinkya More
相关产品推荐
相关产品推荐

