Jest使用spyOn测试方法已调用但覆盖率未覆盖问题求助
问题原因分析
- 核心错误是直接Mock了被测对象本身:你在TestBed配置中使用
useValue: permissionsServiceMock替换了原生的PermissionsService,最终注入到测试上下文的是你自定义的字面量对象,完全没有执行真实PermissionsService类的任何代码,Jest覆盖率自然无法统计到对应方法的执行记录。 - Spy逻辑无效:你通过
jest.spyOn监听的是Mock对象上的hasPermissionAdmin方法,而非真实服务类的方法,测试仅验证了Mock方法是否被调用,和真实业务逻辑完全无关。 - 单元测试原则误用:单元测试只需要Mock被测对象的外部依赖(也就是这个场景中的
AuthService),不能直接Mock被测对象本身,否则完全失去了测试业务逻辑的意义。
解决方案
步骤1:调整TestBed配置,移除对PermissionsService的Mock
只保留对依赖项AuthService的Mock,让TestBed实例化真实的PermissionsService类,才能执行到真实的业务代码。
步骤2:完善AuthService的Mock逻辑
根据测试场景给AuthService的方法配置合理的返回值,支撑PermissionsService的逻辑执行。
步骤3:调整测试用例逻辑
直接调用真实服务的方法验证返回结果,若需要验证调用关系可以对真实服务的方法、或依赖服务的方法做Spy。
修正后的完整测试代码
import { TestBed } from "@angular/core/testing" import { AuthService, PermissionsService } from "services" describe('Permissions Service', () => { let service: PermissionsService; let authService: AuthService; // 仅Mock依赖的AuthService const MockAuthService = { getUserRoles: jest.fn().mockReturnValue(['app_admin_permission']), hasRole: jest.fn().mockImplementation((role: string) => { return role.toLowerCase() === 'app_admin_permission'; }) }; beforeEach(() => { TestBed.configureTestingModule({ providers:[ PermissionsService, // 直接使用真实的服务类,不要Mock {provide: AuthService, useValue: MockAuthService}, ] }); service = TestBed.inject(PermissionsService); authService = TestBed.inject(AuthService); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should have Admin Permission', () => { const hasPermissionSpy = jest.spyOn(service, 'hasPermission'); const result = service.hasPermissionAdmin(); // 验证返回结果符合预期 expect(result).toBe(true); // 验证内部方法调用关系 expect(hasPermissionSpy).toHaveBeenCalledTimes(1); expect(hasPermissionSpy).toHaveBeenCalledWith('App_Admin_permission'); // 也可以验证依赖的AuthService方法被正确调用 expect(authService.hasRole).toHaveBeenCalledWith('App_Admin_permission'); }); // 可补充其他场景用例,比如无权限的场景,覆盖所有逻辑分支 it('should return false when has no admin permission', () => { // 临时修改Mock返回值,覆盖无权限分支 jest.spyOn(authService, 'hasRole').mockReturnValueOnce(false); const result = service.hasPermissionAdmin(); expect(result).toBe(false); }); });
修改后重新运行测试,Jest就能正确统计到PermissionsService所有被执行到的方法的覆盖率了。
内容的提问来源于stack exchange,提问作者TheCoderGuy
相关产品推荐
相关产品推荐

