Angular 16中使用inject()的函数式守卫单元测试方案问询
Angular函数式守卫单元测试注入问题解决方案
核心逻辑
函数式守卫里的inject()必须在Angular的注入上下文里才能正常工作,直接调用守卫函数肯定会报错。正确的做法是用TestBed搭好测试环境,把Mock服务注入进去,然后在注入上下文里执行守卫。
具体步骤
1. 编写Mock服务
先把守卫依赖的AuthService和Router用Mock类模拟出来,只保留守卫用到的方法即可:
class MockAuthService { isLoggedIn = jasmine.createSpy('isLoggedIn').and.returnValue(false); } class MockRouter { createUrlTree = jasmine.createSpy('createUrlTree').and.returnValue({} as UrlTree); }
2. 配置TestBed测试环境
在测试的beforeEach钩子中配置TestBed,提供Mock服务作为依赖:
beforeEach(() => { TestBed.configureTestingModule({ providers: [ { provide: AuthService, useClass: MockAuthService }, { provide: Router, useClass: MockRouter } ] }); });
3. 在注入上下文内执行守卫
用TestBed.runInInjectionContext()包裹守卫调用,让inject()能正常获取Mock服务:
it('用户已登录时跳转到登录页', () => { // 获取Mock服务并预设返回值 const authService = TestBed.inject(AuthService) as MockAuthService; const router = TestBed.inject(Router) as MockRouter; authService.isLoggedIn.and.returnValue(true); // 在注入上下文执行守卫逻辑 const result = TestBed.runInInjectionContext(() => { return inverseAuthGuard({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot); }); // 断言执行结果 expect(router.createUrlTree).toHaveBeenCalledWith(['/login']); expect(result).toEqual(router.createUrlTree(['/login'])); });
之前方法报错的原因
- 直接调用
inverseAuthGuard():没有处于Angular的注入上下文,inject()无法获取服务,触发NG0203错误。 - 尝试将
inverseAuthGuard作为提供者:函数式守卫并非可注入服务,TestBed无法找到对应提供者,触发NullInjectorError。
额外提示
- 如果守卫用到
ActivatedRouteSnapshot或RouterStateSnapshot的具体属性(比如路由参数),需要在Mock对象中补充对应值,不要直接空转类型。 - Mock服务的方法可以用
jasmine.createSpy或jest.fn()实现,方便断言方法的调用情况与传参是否正确。
内容的提问来源于stack exchange,提问作者faklyasgy
相关产品推荐
相关产品推荐

