如何在Mocha中Mock并扩展Screeps的Creep类及其原型?
解决Screeps TypeScript测试中Creep原型扩展的ReferenceError问题
这个错误的核心原因很明确:你的测试环境里完全没有Screeps原生的Creep类定义,当你导入prototypes.ts时,代码尝试访问Creep.prototype,但找不到这个类,自然就抛出了ReferenceError。下面是我亲测有效的解决步骤:
1. 先在测试环境中定义基础的Creep类
因为@types/screeps提供的Creep是一个接口,我们需要创建一个空的类来实现这个接口,并且把它挂载到全局对象上,这样原型扩展代码就能找到目标了。
你可以在测试文件最前面添加这段代码,或者把它抽成单独的mock文件复用:
import type { Creep as ScreepsCreep } from '@types/screeps'; // 创建一个基础的Creep类,实现Screeps的Creep接口 class Creep implements ScreepsCreep { // 只需要添加必要的基础属性,或者用索引签名绕过未实现的属性检查 id = 'test-creep-id'; name = 'test-creep'; [key: string]: any; // 允许任意属性,避免类型报错 } // 将这个类挂载到全局,让prototypes.ts能访问到 global.Creep = Creep;
2. 调整导入顺序,确保Creep定义在前
原来的导入顺序是先加载原型扩展,这时候Creep还没定义,所以一定要先完成Creep的全局挂载,再导入prototypes.ts:
// 先导入测试依赖和mock基础 import { Game, Memory } from "./mock"; import { assert } from "chai"; import { Substitute, Arg } from "@fluffy-spoon/substitute"; import type { Creep as ScreepsCreep } from '@types/screeps'; // 第一步:定义并挂载Creep到全局 class Creep implements ScreepsCreep { id = 'test-creep-id'; name = 'test-creep'; [key: string]: any; } global.Creep = Creep; // 第二步:现在再导入原型扩展和业务代码 import "../constants"; import "../../src/tasks/prototypes"; import { Task } from "tasks/Task";
3. 正确创建Mock Creep实例
现在测试环境已经有了Creep的定义,你可以用@fluffy-spoon/substitute正常创建Mock实例了。注意如果需要模拟task属性的get/set逻辑,可以给Mock设置返回值或行为:
describe("tasks", () => { beforeEach(() => { // 重置全局Game和Memory // @ts-ignore global.Game = _.clone(Game) as Game; // @ts-ignore global.Memory = _.clone(Memory); }); it("Creep should have extended prototype", () => { const testCreep = Substitute.for<ScreepsCreep>(); // 根据你的task getter逻辑,设置Mock的返回值 testCreep.task.returns(null); // 或者你预期的初始值 const task = testCreep.task; assert.isNotNull(task); // 这里根据你的实际逻辑调整断言 }); });
可选:抽离Mock代码到单独文件
如果多个测试文件都需要用到Creep的Mock,把上面的Creep类定义放到src/test/mock-creep.ts里,然后在测试文件里导入并挂载:
// mock-creep.ts import type { Creep as ScreepsCreep } from '@types/screeps'; export class Creep implements ScreepsCreep { id = 'test-creep-id'; name = 'test-creep'; [key: string]: any; }
在测试文件中使用:
import { Creep } from './mock-creep'; global.Creep = Creep;
这样做的好处是避免重复代码,保持测试文件整洁。
内容的提问来源于stack exchange,提问作者thmsn
相关产品推荐
相关产品推荐

