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

使用Mocha/Sinon为TypeScript模拟marantz-avr依赖失败求助

解决MarantzPlugin单元测试中模拟marantz-avr库的问题

你的测试代码里有几个关键问题导致模拟没生效,还有模块找不到的错误,我来一步步帮你解决:

1. 当前测试的核心问题

  • 你错误地尝试stub AVReceiver.prototype.AVReceiver——这根本不是构造函数的正确位置,构造函数本身是模块导出的顶级函数,不是原型上的属性。
  • 直接用require导入真实模块后,CommonJS的模块缓存机制会让MarantzPlugin依然使用原始的AVReceiver,你的stub无法覆盖它。
  • 测试里调用了marantz.setPowerState('on'),但你的类里实际暴露的方法是turnPowerOn,这是个小笔误。

2. 推荐解决方案:用proxyquire替换依赖

proxyquire是专门用来在CommonJS环境中替换模块依赖的工具,它能让你在加载MarantzPlugin时,把真实的marantz-avr替换成我们的模拟对象,完美解决模块缓存的问题。

步骤1:安装依赖

npm install proxyquire sinon --save-dev

步骤2:编写正确的测试代码

import { suite, test, before } from 'mocha-typescript';
import * as assert from 'assert';
import * as sinon from 'sinon';
import * as proxyquire from 'proxyquire';

// 定义模拟的AVReceiver类型(可选,让TypeScript不报错)
type MockAVReceiver = {
  setPowerState: sinon.SinonStub<['on' | 'off'], Promise<any>>;
};

@suite
class MarantzPluginTest {
  private marantzPlugin: any;
  private mockAVReceiverConstructor: sinon.SinonStub<[string], MockAVReceiver>;
  private mockSetPowerState: sinon.SinonStub;

  before(() => {
    // 1. 创建setPowerState的stub,注意要返回Promise(原方法是异步的)
    this.mockSetPowerState = sinon.stub().resolves({ success: true });

    // 2. 创建AVReceiver构造函数的stub,返回包含mock方法的实例
    this.mockAVReceiverConstructor = sinon.stub().returns({
      setPowerState: this.mockSetPowerState
    });

    // 3. 用proxyquire加载MarantzPlugin,替换marantz-avr的导出
    const MarantzPlugin = proxyquire('./', {
      'marantz-avr': this.mockAVReceiverConstructor
    }).default;

    // 4. 实例化插件
    this.marantzPlugin = new MarantzPlugin({
      id: 'MARANTZ',
      settings: {
        ip: '192.168.178.2'
      }
    });
  });

  @test 'should call setPowerState with "on" when turnPowerOn is invoked'() {
    // 调用类的方法
    this.marantzPlugin.turnPowerOn();

    // 验证构造函数是否用正确的IP被调用
    assert.ok(this.mockAVReceiverConstructor.calledWith('192.168.178.2'));
    // 验证setPowerState是否被调用,参数是'on'
    assert.ok(this.mockSetPowerState.calledWith('on'));
  }
}

3. 为什么之前的方法会报错?

你提到参考了Sinon的链接接缝文档后出现Cannot find module 'marantz-avr'错误,大概率是因为你在替换模块时没有正确设置模块路径,或者你的TypeScript配置(比如moduleResolution)影响了模块查找。而proxyquire会自动处理模块路径的问题,不需要手动修改模块加载逻辑,更适合这种场景。

4. 额外注意点

  • 原类中的turnPowerOn方法里,then的写法有点问题:then(res => res, error => console.error(error))其实可以简化为.catch(error => console.error(error)),而且如果要测试错误场景,你可以让mock的setPowerStatereject,然后验证错误处理逻辑。
  • 如果你不想用proxyquire,也可以用rewire来修改MarantzPlugin内部的require变量,但proxyquire的写法更直观。

内容的提问来源于stack exchange,提问作者Bas van Dijk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:34:33