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

测试依赖HTTP请求的Angular路由守卫报错,如何解决?

问题:Angular守卫测试报错 TypeError: this.auth.isAuthenticated(...).pipe is not a function

我在测试Angular项目的认证守卫时遇到了这个错误,想请教大家怎么正确编写测试用例。以下是我的相关代码:

认证服务代码

isAuthenticated () { 
  const token = localStorage.getItem('token'); 
  if (token) { 
    return this.verifyToken(token).pipe( 
      map(data => true), 
      catchError (error => of(false)) 
    ); 
  } 
  return of(false); 
} 

verifyToken (token: string): Observable<any> { 
  const data = {'token': token}; 
  return this.http.post('url/verify/', data); 
}

守卫的canActivate方法

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 
  return this.auth.isAuthenticated().pipe( 
    map(data => { 
      if (data) { 
        this.router.navigate(['/url/']); 
      } 
      return !data; 
    }) 
  ); 
}

测试代码

let guard: Guard; 
let service: Service; 

beforeEach(() => { 
  TestBed.configureTestingModule({ 
    imports: [CommonModule], 
    providers: [ 
      Service, 
      Guard, 
    ] 
  }).compileComponents(); 
  guard = TestBed.get(Guard); 
  service = TestBed.get(Service); 
}); 

it("can't see login page when he is logged in", fakeAsync(() =>{ 
  spyOn(service, 'isAuthenticated').and.callFake(()=>{return true;}); 
  guard.canActivate(new ActivatedRouteSnapshot(), mockSnapshot).subscribe( 
    x => expect(x).toBeFalsy() 
  ); 
}));

错误提示

TypeError: this.auth.isAuthenticated(...).pipe is not a function


解决方案

嘿,这个问题的根源很容易找到:你在spyOn的时候让isAuthenticated直接返回了普通布尔值true,但实际上这个方法的返回类型是Observable,只有Observable才有pipe方法,普通布尔值当然没有,所以才会抛出这个错误。

你只需要把callFake的返回值改成发出true的Observable就行,用RxJS的of操作符来实现:

// 先确保导入了of操作符
import { of } from 'rxjs';

it("can't see login page when he is logged in", fakeAsync(() => {
  // 把return true改成return of(true)
  spyOn(service, 'isAuthenticated').and.callFake(() => of(true));
  
  guard.canActivate(new ActivatedRouteSnapshot(), mockSnapshot).subscribe(
    x => expect(x).toBeFalsy()
  );
}));

另外还有几个小细节可以优化一下,让测试更健壮:

  1. 别忘了在测试文件顶部导入of操作符,不然会报错
  2. 你的测试模块里没有导入HttpClientTestingModule,如果后续要测试verifyToken这类依赖HTTP请求的方法,一定要加上这个模块
  3. 守卫里用到了Router,最好给它提供一个mock,避免this.router.navigate在测试中抛出错误,推荐用RouterTestingModule来配置:
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [CommonModule, HttpClientTestingModule, RouterTestingModule],
    providers: [Service, Guard]
  }).compileComponents();
  
  // Angular 9+推荐用inject代替get,类型更安全
  guard = TestBed.inject(Guard);
  service = TestBed.inject(Service);
});

这样修改之后,你的测试应该就能正常运行了,因为现在isAuthenticated返回的是一个合法的Observable,pipe方法就能正常调用啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:30:42