TypeScript中Mixin类无法被Rhum模拟的技术求助
解决Rhum无法模拟Mixin生成类的问题
我之前也碰到过类似的动态类模拟坑,结合你的代码和环境(Deno 1.19.3、TypeScript 4.5.2、Rhum v1.1.10),咱们来一步步拆解问题和可行的解决办法:
问题根源
你通过WithGameProperty()这个Mixin函数动态生成了PlayersEngine类,这类动态派生的类和普通类结构有差异:
- Mixin给类注入了私有属性
game和对应的存取器Game - Rhum的
mock().create()方法在处理这种动态继承的类时,可能无法正确解析类的原型链、私有成员结构,导致初始化mock实例时抛出错误
解决方案
方案1:模拟原始基类而非Mixin后的类
既然PlayersEngine是基于内部匿名类生成的,咱们可以先把这个基类抽出来单独定义,模拟原始基类后再用Mixin包裹它:
// 抽离原始业务类 class BasePlayersEngine { onNextGenerationReady(listener: () => void): void { // add listener to react on an event } prepareNextGeneration(): void { // do some stuff and trigger an event } } // 应用Mixin生成最终类 const PlayersEngine = WithGameProperty()(BasePlayersEngine); // 模拟原始基类(Rhum能正常处理普通类) Rhum.mock(BasePlayersEngine).create(); // 如果需要验证Mixin的Game属性逻辑,可以单独写测试用例覆盖
这种方式把Mixin逻辑和业务类逻辑拆分,既让Rhum能正常工作,也能更清晰地测试各个模块。
方案2:手动实现Mock类替代自动模拟
如果必须模拟PlayersEngine,可以手动写一个Mock类,完全控制mock的行为,避开Rhum的自动解析问题:
class MockPlayersEngine extends PlayersEngine { // 覆盖需要模拟的方法 override onNextGenerationReady(listener: () => void): void { // 自定义mock逻辑,比如记录调用次数、参数 } override prepareNextGeneration(): void { // 自定义mock逻辑 } // 可选:重写Game存取器来控制返回值 override get Game(): IGame { return new NullGame(); } } // 使用手动Mock类 const mockPe = new MockPlayersEngine();
这种方式灵活性最高,完全不会触发Rhum的内部解析异常。
方案3:升级Rhum版本
你当前使用的Rhum v1.1.10版本比较老旧,后续的v2.x版本大概率修复了动态类/Mixin类的模拟问题。可以尝试升级到最新稳定版:
// 替换导入的Rhum版本 import { Rhum } from "https://deno.land/x/rhum@v2.0.0/mod.ts";
注意大版本升级可能有API变更,需要稍微调整测试代码的写法。
方案4:手动调整类的原型链标识
如果不想升级,可以先检查PlayersEngine的原型链结构,帮助Rhum识别类的构造函数:
// 打印原型链,查看结构是否异常 console.log(Object.getPrototypeOf(PlayersEngine)); console.log(PlayersEngine.prototype); // 可选:手动给动态类设置构造函数名称 Object.defineProperty(PlayersEngine, 'name', { value: 'PlayersEngine' });
有时候Rhum无法识别匿名动态类的构造函数,手动设置名称后可能能解决问题。
额外测试建议
- 单独测试Mixin函数:把
WithGameProperty()的逻辑单独写测试用例,验证它是否正确给类注入了属性和存取器,这样能降低测试耦合度。 - 结合Deno内置测试工具:Deno自带的
Deno.test()和断言库可以和Rhum配合使用,每个测试用例只验证一个功能点,排查问题会更高效。
内容的提问来源于stack exchange,提问作者dominikj111
相关产品推荐
相关产品推荐

