Angular服务单元测试报错:service.config未定义(main.js中)
Angular AppConfigService单元测试:config未定义错误排查
我编写了一个用于动态获取Angular应用配置的AppConfigService,单元测试中第一个验证服务实例创建的测试通过,但第二个验证config中apiUri值的测试失败,Karma抛出TypeError: service.config is undefined错误。
服务代码
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class AppConfigService { private appConfig: any; constructor(private http: HttpClient) { } async loadAppConfig(): Promise<any> { try { const response = await this.http.get('/assets/data/appConfig.json') .toPromise() this.appConfig = response; return this.appConfig; } catch (err) { return Promise.reject(err) } } get config(): any { return this.appConfig; } }
原测试代码
import { HttpClient } from '@angular/common/http'; import { AppConfigService } from './app-config.service'; describe('AppConfigService', () => { let service: AppConfigService; let client: HttpClient; beforeEach(() => { service = new AppConfigService(client) }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should output correct apiUri', () => { expect(service.config.apiUri).toBe('http://api:8080/query'); }); });
Karma报错信息
Firefox 102.0 (Linux x86_64) AppConfigService should output correct apiUri FAILED TypeError: service.config is undefined in main.js (line 46) 501/<<@main.js:46:9 invoke@polyfills.js:382:26 onInvoke@vendor.js:102041:39 invoke@polyfills.js:381:52 run@polyfills.js:144:43 runInTestZone@vendor.js:102321:34 wrapTestInZone/<@vendor.js:102336:20 <Jasmine> invokeTask@polyfills.js:416:31 runTask@polyfills.js:188:47 drainMicroTaskQueue@polyfills.js:592:35
错误原因
appConfig未初始化:appConfig私有变量初始值为undefined,仅在loadAppConfig()方法成功执行后才会被赋值。原测试未调用loadAppConfig(),直接访问service.config自然返回undefined,无法读取apiUri。- HttpClient未模拟:原测试将未初始化的
client传入服务构造函数,即使调用loadAppConfig(),实际的http.get也会报错,无法获取配置。 - 异步逻辑未处理:
loadAppConfig()是异步方法,原测试未处理Promise异步流程,断言会在配置加载完成前执行,导致结果不符合预期。
修正后的测试代码
import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { AppConfigService } from './app-config.service'; describe('AppConfigService', () => { let service: AppConfigService; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [AppConfigService] }); service = TestBed.inject(AppConfigService); httpMock = TestBed.inject(HttpTestingController); }); afterEach(() => { // 验证所有HTTP请求均已处理 httpMock.verify(); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should output correct apiUri', async () => { // 模拟配置文件返回数据 const mockConfig = { apiUri: 'http://api:8080/query' }; // 调用异步加载方法 const config = await service.loadAppConfig(); // 捕获HTTP请求并返回模拟数据 const req = httpMock.expectOne('/assets/data/appConfig.json'); expect(req.request.method).toBe('GET'); req.flush(mockConfig); // 断言配置值正确 expect(config.apiUri).toBe('http://api:8080/query'); expect(service.config.apiUri).toBe('http://api:8080/query'); }); });
修正说明
- 使用
TestBed配合HttpClientTestingModule模拟HttpClient,避免发送真实HTTP请求,保证测试独立性。 - 通过
async/await处理loadAppConfig()的异步逻辑,确保断言在配置加载完成后执行。 - 利用
HttpTestingController捕获HTTP请求,返回预定义的模拟配置数据,精准控制测试场景。 - 增加
afterEach钩子验证所有HTTP请求均被处理,避免测试污染。
内容的提问来源于stack exchange,提问作者stacky_bobo
相关产品推荐
相关产品推荐

