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

Angular 16函数式守卫单元测试问题:未登录场景验证失败

Angular 16 函数式守卫未登录场景单元测试修正方案

问题根源

你当前的测试错误在于:executeGuard是守卫返回的函数实例,而非守卫执行后的返回值。直接断言一个函数等于false必然失败,因为函数本身是一个对象,不是布尔值。

修正后的测试代码

describe('authenticationGuard', () => {
    let cognitoServiceSpy: jasmine.SpyObj<CognitoService>;
    let userContextServiceSpy: jasmine.SpyObj<UserContextService>;
    let userServiceSpy: jasmine.SpyObj<UserService>;
    let mockRouter: jasmine.SpyObj<Router>;

    // 模拟路由快照参数
    const mockRouteSnapshot = {} as ActivatedRouteSnapshot;
    const mockRouterStateSnapshot = { url: '/test' } as RouterStateSnapshot;

    beforeEach(() => {
        cognitoServiceSpy = jasmine.createSpyObj('CognitoService', ['currentAuthenticatedUser']);
        userServiceSpy = jasmine.createSpyObj('UserService', ['getCurrentUserInfos']);
        userContextServiceSpy = jasmine.createSpyObj('UserContextService', ['getUserInfos', 'setUserInfos']);
        mockRouter = jasmine.createSpyObj('Router', ['navigate']);

        // Mock localStorage 避免测试环境报错
        spyOn(localStorage, 'setItem');

        TestBed.configureTestingModule({
            providers: [
                { provide: CognitoService, useValue: cognitoServiceSpy },
                { provide: UserService, useValue: userServiceSpy },
                { provide: UserContextService, useValue: userContextServiceSpy },
                { provide: Router, useValue: mockRouter }
            ]
        });
    });

    it('should redirect to login and return false when user is not authenticated', fakeAsync(async () => {
        // 模拟未登录状态
        cognitoServiceSpy.currentAuthenticatedUser.and.resolveTo(false);

        // 获取守卫函数并执行
        const guardFn = TestBed.runInInjectionContext(() => {
            return authenticationGuard(userContextServiceSpy);
        });
        const result = await guardFn(mockRouteSnapshot, mockRouterStateSnapshot);

        // 验证断言
        expect(localStorage.setItem).toHaveBeenCalledWith('redirect', JSON.stringify('/test'));
        expect(mockRouter.navigate).toHaveBeenCalledWith(['authentification']);
        expect(result).toBeFalse();
    }));
});

关键修正点

  • 执行守卫函数:获取守卫返回的guardFn后,必须调用它并传入ActivatedRouteSnapshot和RouterStateSnapshot参数,才能得到守卫的实际返回值。
  • 处理异步逻辑:守卫是async函数,返回Promise<boolean>,需要用await获取结果,结合fakeAsync确保异步逻辑完成。
  • Mock localStorage:测试中调用了localStorage.setItem,需要用spyOn模拟该方法,避免测试环境中出现未预期的副作用。
  • 简化依赖注入:不需要额外提供ActivatedRoute和RouterState,因为守卫执行时直接传入模拟的快照对象即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:02:49