Angular 15单元测试报错:无法读取只读常量属性,原因何在?
Angular 15 + Karma单元测试静态常量初始化报错问题
使用Angular 15.2.10搭配Karma 6.3.12运行单元测试时遇到报错,升级Karma到6.4.3后问题依旧。奇怪的是,代码通过ng serve运行完全正常,但测试环境下报错指向只读静态常量。
完整栈跟踪信息
27 03 2024 17:19:00.500:WARN [karma-server]: `autowatch` and `singleRun` are both `false`. In order to execute tests use `karma run`. √ Browser application bundle generation complete. 27 03 2024 17:19:19.887:INFO [karma-server]: Karma v6.4.3 server started at http://localhost:9876/ 27 03 2024 17:19:19.890:INFO [launcher]: Launching browsers Edge with concurrency unlimited 27 03 2024 17:19:19.895:INFO [launcher]: Starting browser Edge 27 03 2024 17:19:28.277:INFO [Edge 122.0.0.0 (Windows 10)]: Connected on socket ZJvt9iD1pJGZzp_IAAAB with id 72359205 Edge 122.0.0.0 (Windows 10) ERROR An error was thrown in afterAll Uncaught TypeError: Cannot read properties of undefined (reading 'restCallType') TypeError: Cannot read properties of undefined (reading 'restCallType') at Function.<static_initializer> (localhost:9876/_karma_webpack_/webpack:/src/app/commons/core/utility/constants.ts:613:20) at Module.20467 (localhost:9876/_karma_webpack_/webpack:/src/app/commons/core/utility/constants.ts:6:23) at __webpack_require__ (localhost:9876/_karma_webpack_/webpack:/webpack/bootstrap:19:1) at Module.84225 (localhost:9876/_karma_webpack_/main.js:5733:89) at __webpack_require__ (localhost:9876/_karma_webpack_/webpack:/webpack/bootstrap:19:1) at Module.55041 (localhost:9876/_karma_webpack_/main.js:63:98) at __webpack_require__ (localhost:9876/_karma_webpack_/webpack:/webpack/bootstrap:19:1) at Module.24882 (localhost:9876/_karma_webpack_/main.js:14:72) at __webpack_require__ (localhost:9876/_karma_webpack_/webpack:/webpack/bootstrap:19:1) at __webpack_exec__ (localhost:9876/_karma_webpack_/main.js:27950:48)
相关代码文件
groups-search.component.spec.ts
import {ComponentFixture, TestBed} from '@angular/core/testing'; import {GroupsSearchComponent} from './groups-search.component'; describe('GroupsSearchComponent', () => { let component: GroupsSearchComponent; let fixture: ComponentFixture<GroupsSearchComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [GroupsSearchComponent] }) .compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(GroupsSearchComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });
constants.ts
import {Injectable} from '@angular/core'; @Injectable() export class Constants { // ... 其他常量 ... public static readonly restCallType: any = { GET_ALL: "GET_ALL", // ... 其他值 ... } // ... 其他常量 ... public static readonly services: any = { GET_ALL_GROUPS: { code: "GET_ALL_GROUPS", type: Constants.restCallType.GET_ALL, url: "api/v1/group/findByParams" } } // ... 其他常量 ... }
临时解决与疑问
将type: Constants.restCallType.GET_ALL,替换为type: "GET_ALL",后,测试可以正常运行,但不清楚具体原因。
问题原因与解决方案
问题根源
这是类静态成员初始化顺序导致的问题:
JavaScript/TypeScript中类的静态成员是从上到下依次初始化的。正常运行环境(ng serve)下,Webpack的打包优化会确保依赖项先完成初始化;但Karma测试环境的打包/加载逻辑不同,可能出现services初始化时,restCallType还未完成赋值的情况,导致Constants.restCallType为undefined,进而抛出读取GET_ALL的错误。
可靠修复方案
有三种可行的修复方式:
- 调整静态成员顺序:确保
restCallType的定义在services之前,让依赖项先完成初始化。 - 使用立即执行函数延迟初始化:避免直接依赖初始化顺序,在
services被访问时再执行初始化:
public static readonly services: any = (() => ({ GET_ALL_GROUPS: { code: "GET_ALL_GROUPS", type: Constants.restCallType.GET_ALL, url: "api/v1/group/findByParams" } }))();
- 改用TypeScript枚举:对于固定的枚举值,推荐用枚举替代对象常量,从根源避免初始化顺序问题:
export enum RestCallType { GET_ALL = "GET_ALL" // ... 其他值 ... } @Injectable() export class Constants { public static readonly services: any = { GET_ALL_GROUPS: { code: "GET_ALL_GROUPS", type: RestCallType.GET_ALL, url: "api/v1/group/findByParams" } } }
内容的提问来源于stack exchange,提问作者mistermaster
相关产品推荐
相关产品推荐

