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

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的错误。

可靠修复方案

有三种可行的修复方式:

  1. 调整静态成员顺序:确保restCallType的定义在services之前,让依赖项先完成初始化。
  2. 使用立即执行函数延迟初始化:避免直接依赖初始化顺序,在services被访问时再执行初始化:
public static readonly services: any = (() => ({
    GET_ALL_GROUPS: {
        code: "GET_ALL_GROUPS",
        type: Constants.restCallType.GET_ALL,
        url: "api/v1/group/findByParams"
    }
}))();
  1. 改用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:13:19