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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:27:01