如何测试Angular中返回Promise内的subscribe函数?
解决Angular ConfigService Promise测试超时/错误通过问题
你的测试出现超时或错误通过的核心原因有两个:一是没有模拟HTTP请求的响应,导致Promise一直处于pending状态;二是测试未正确处理异步逻辑,Jasmine会直接结束测试而不等待Promise resolve。另外你的服务代码里还有两个小问题需要先修正。
第一步:修正服务代码
服务里的displayJsonFile未定义,应该作为参数传入load方法,同时静态属性appSettings要正确引用类本身:
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; export interface IAppConfig { env: { name: string; }; features: { [key: string]: boolean; }; } @Injectable({ providedIn: 'root', }) export class ConfigService { static appSettings: IAppConfig; constructor(private http: HttpClient) {} load(displayJsonFile: boolean) { // 接收参数控制加载哪个文件 const jsonFile = displayJsonFile ? `../../../../assets/.json1` : `../../../../assets/.json2`; return new Promise<IAppConfig>((resolve) => { this.http.get<IAppConfig>(jsonFile).subscribe((res) => { ConfigService.appSettings = res; // 正确引用静态属性 resolve(res); }); }); } }
第二步:修正测试代码
测试需要处理异步逻辑,同时用HttpTestingController模拟HTTP响应:
import { TestBed, async } from '@angular/core/testing'; import { ConfigService } from './config-service.service'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { IAppConfig } from './config-service.service'; describe('ConfigService', () => { let service: ConfigService; let httpMock: HttpTestingController; const mockJson1Config: IAppConfig = { env: { name: 'json1', }, features: { feature1: true, feature2: true, }, }; const mockJson2Config: IAppConfig = { env: { name: 'json2', }, features: { feature1: false, feature2: true, }, }; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule] }); service = TestBed.inject(ConfigService); httpMock = TestBed.inject(HttpTestingController); }); afterEach(() => { // 验证所有HTTP请求都已被处理,避免内存泄漏 httpMock.verify(); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should load .json1 when displayJsonFile is true', async () => { // 调用load方法,传入参数 const result = await service.load(true); // 匹配对应的HTTP请求 const req = httpMock.expectOne('../../../../assets/.json1'); // 模拟返回数据 req.flush(mockJson1Config); // 验证Promise结果和静态属性 expect(result).toEqual(mockJson1Config); expect(ConfigService.appSettings).toEqual(mockJson1Config); }); it('should load .json2 when displayJsonFile is false', (done) => { // 也可以用done回调处理异步 service.load(false).then(res => { expect(res).toEqual(mockJson2Config); expect(ConfigService.appSettings).toEqual(mockJson2Config); done(); // 通知Jasmine测试完成 }); const req = httpMock.expectOne('../../../../assets/.json2'); req.flush(mockJson2Config); }); });
关键说明
- 异步处理:用
async/await或done回调让Jasmine等待Promise完成,避免测试提前结束。 - HTTP模拟:调用
load后必须用httpMock.expectOne匹配请求URL,再用flush返回模拟数据,这样subscribe才会触发,Promise才能resolve。 - 验证请求:
afterEach里的httpMock.verify()确保没有未处理的HTTP请求,避免测试污染。 - 类型安全:给
http.get和Promise加上泛型<IAppConfig>,避免any类型导致的潜在问题。
内容的提问来源于stack exchange,提问作者OHello
相关产品推荐
相关产品推荐

