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

Angular7中Promise服务Jasmine测试代码覆盖不生效及Mock覆盖获取

解决Angular 7中Promise返回型服务的Jasmine测试覆盖率问题

首先得点明你当前测试的核心问题:你直接用spyOn(myService, 'getAllRecords')把整个被测方法替换成了一个假的Promise实现,这就导致getAllRecords内部的真实逻辑(包括Promise创建、httpService调用、subscribe回调)根本没被执行。Istanbul覆盖率工具只会统计实际运行过的代码,自然不会把这段没跑过的代码算进覆盖率里。

要解决这个问题,你需要测试方法的真实业务逻辑,而不是直接mock整个被测方法。正确的思路是mock服务的依赖(也就是HttpService和HttpClient),让被测方法的真实代码完整跑起来,这样覆盖率工具才能正确统计代码执行情况。

步骤1:正确配置测试环境,mock依赖

先在beforeEach里用TestBed搭建测试环境,同时创建依赖的spy对象来模拟它们的行为:

describe('MyService', () => {
  let myService: MyService;
  let mockHttpService: jasmine.SpyObj<HttpService>;

  beforeEach(() => {
    // 创建HttpService的spy对象,指定要mock的方法
    mockHttpService = jasmine.createSpyObj('HttpService', ['makeHttpGetRequest']);

    TestBed.configureTestingModule({
      providers: [
        MyService,
        // mock HttpClient,这里我们不需要它的实际逻辑,所以用空spy即可
        { provide: HttpClient, useValue: jasmine.createSpyObj('HttpClient', ['get']) },
        // 注入mock的HttpService
        { provide: HttpService, useValue: mockHttpService }
      ]
    });

    // 获取真实的MyService实例
    myService = TestBed.inject(MyService);
  });
});

步骤2:编写测试用例,覆盖完整逻辑

现在我们可以针对getAllRecords的真实逻辑编写测试,需要覆盖请求成功和失败两种场景:

场景1:请求成功,Promise正常resolve

it('should resolve with response body when http request succeeds', (done) => {
  // 准备mock的响应数据
  const mockResponse = { body: { id: 1 } };
  // 让mock的makeHttpGetRequest返回一个成功的Observable
  mockHttpService.makeHttpGetRequest.and.returnValue(of(mockResponse));

  myService.getAllRecords(null).then((result) => {
    // 验证返回结果是否正确
    expect(result).toEqual({ id: 1 });
    // 验证httpService的方法是否被正确调用
    expect(mockHttpService.makeHttpGetRequest).toHaveBeenCalledWith(`${ApiUrl.getUrl}`, null);
    done();
  });
});

场景2:请求失败,Promise被reject

it('should reject when http request fails', (done) => {
  // 让mock的makeHttpGetRequest返回一个失败的Observable
  mockHttpService.makeHttpGetRequest.and.returnValue(throwError(() => new Error('test error')));

  myService.getAllRecords(null).catch(() => {
    // 验证Promise确实被reject
    expect(true).toBeTrue();
    // 验证httpService的方法是否被调用
    expect(mockHttpService.makeHttpGetRequest).toHaveBeenCalled();
    done();
  });
});

关于Mock方法的代码覆盖率

其实我们不需要统计mock对象(比如这里的mockHttpService)的代码覆盖率——mock的作用是模拟依赖的行为,我们的测试目标是**被测服务(MyService)**的代码逻辑。只要按照上面的方式让getAllRecords的真实代码完整执行,Istanbul就会正确统计这段代码的覆盖率了。

现在重新运行测试,再看覆盖率报告,getAllRecords内部的代码应该会被正确统计进去了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:59:57