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

Angular单元测试:subscribe无返回值致portfolioType为空的问题

Angular组件单元测试中portfolioType值为空的原因及解决方法

在Angular项目中,组件通过getPortfolioType方法调用dataService的getPortfolioTypeList接口,在subscribe回调中为portfolioType赋值,但单元测试调用该方法后,portfolioType始终为空。


相关代码

组件代码(component.ts)

getPortfolioType() {
  this.dataService.getPortfolioTypeList()
    .subscribe((response: any) => {
      this.portfolioType = response.payload.portfolioList;
    })
}

DataService代码(data.service.ts)

public getPortfolioTypeList(): any {
  return this.http.getData('/portfolio/portfolioTypeList');
}

HttpService代码(http.service.ts)

getData(action: any, data: any = {}): any {
  const url = environment.API_URL + action;
  const params = Object.keys(data);
  let httpParams = new HttpParams();

  if (params.length) {
    params.forEach((key: string) => {
      httpParams = httpParams.append(key, data[key]);
    });
  }

  return this.http.get(url, {params: httpParams});
}

已通过的服务测试用例

it('should pass service getPortfolioTypeList', () => {
  const test = {
    "test": "test"
  }
  let result: any;
  dataService.getPortfolioTypeList().subscribe(t => {
    result = t;
  });
  const req = httpMock.expectOne({
    method: "GET",
    url: environment.API_URL + '/portfolio/portfolioTypeList'
  });

  req.flush([test]);

  expect(result[0]).toEqual(test);
});

失败的组件测试用例

it('Get data from getPortfolioType', () => {
  component.getPortfolioType();
  console.log(component.portfolioType); // <<<< is empty
});

原因分析

  1. 异步操作未完成:getPortfolioType内部是异步HTTP请求,调用component.getPortfolioType()后,代码会直接执行后续的console.log,此时subscribe回调还未触发,portfolioType自然为空。
  2. 未模拟HTTP请求并返回数据:组件测试中没有像服务测试那样,用HttpTestingController捕获请求并返回模拟数据,导致dataService的Observable从未发出值,回调也就不会执行。

解决方法

修改组件测试用例,完成以下步骤:

  1. 调用组件方法后,捕获对应的HTTP请求;
  2. 用flush返回符合组件期望格式的模拟数据;
  3. 触发变更检测(若组件使用OnPush策略则需要);
  4. 断言portfolioType的值。

修正后的测试用例示例:

it('Get data from getPortfolioType', () => {
  // 调用组件方法
  component.getPortfolioType();

  // 捕获HTTP请求
  const req = httpMock.expectOne({
    method: "GET",
    url: environment.API_URL + '/portfolio/portfolioTypeList'
  });

  // 返回符合组件期望格式的模拟数据
  const mockResponse = {
    payload: {
      portfolioList: [{ id: 1, name: 'Type A' }]
    }
  };
  req.flush(mockResponse);

  // 触发变更检测
  fixture.detectChanges();

  // 断言portfolioType已被赋值
  expect(component.portfolioType).toEqual(mockResponse.payload.portfolioList);
});

内容的提问来源于stack exchange,提问作者aleksandr_sven

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 11:25:32