You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:04:02