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
相关产品推荐
相关产品推荐

