【问题标题】:How to use ProxyRequire to mock NodeJs test如何使用 ProxyRequire 模拟 NodeJs 测试
【发布时间】:2021-11-07 12:52:06
【问题描述】:

我正在为以下文件编写单元测试用例

//filename: a.js

var amqp = require("amqplib");

class RMQ {
  constructor(connectionURI) {
    this.URI = connectionURI;
  }
  async getInstance() {
    var connection = await amqp.connect(this.URI);
    this.connection = connection;
    return connection;
  }
}

const RMQ_INSTANCE = new RMQ(process.env.RMQ_URL);

module.exports = {
  RMQ_INSTANCE,
};

我在下面的文件中使用实例RMQ_INSTANCE

// filename: b.js

const { RMQ_INSTANCE } = require("./a");

module.exports.publishEmail = async function(message) {
  var connection = await RMQ_INSTANCE.getInstance();
  var channel = await connection.createChannel();
  var exchange = "some_exchange";
  var key = "some_key";
  var msg = JSON.stringify(message);
  await channel.assertExchange(exchange, "topic", { durable: false });
  await channel.publish(exchange, key, Buffer.from(msg));
  setTimeout(function () {
    connection.close();
  }, 500);
}

我正在使用proxyrequire 模拟b.js 中的RMQ_INSTANCE

// filename: b.test.js

var proxyrequire = require("proxyquire").noCallThru();
var sinon = require("sinon");
const { assert } = require("sinon");

class fakeRMQClass {
  constructor(connectionURI) {
    this.URI = connectionURI;
  }
  async getInstance() {
    var connection = getFakeRMQStub()
    return connection;
  }
}

var producerTest = function () {
  it("producer connection - success test", async function () {
    var fakeRMQInstance = new fakeRMQClass("fake_url");
    var rmqUtils = proxyrequire("../path/to/b.js", {
      "./a": fakeRMQInstance
    });
    await rmqUtils.publishEmail("fake_msg");
  });
  afterEach(function () {
    sinon.verifyAndRestore();
  });
};
describe("test_producer", producerTest);

但我看到模拟无法正常工作。谁能帮我正确地模拟一下?

【问题讨论】:

    标签: javascript node.js unit-testing sinon


    【解决方案1】:

    由于RMQ_INSTANCE 是一个对象,你可以使用sinon.stub(obj, 'method') 来存根它的方法,你不需要使用proxyquire 包。

    既然要测试b模块,那么b模块只关心它所依赖的RMQ_INSTANCE的接口,具体实现无所谓。

    b.js:

    const { RMQ_INSTANCE } = require('./a');
    
    module.exports.publishEmail = async function (message) {
      var connection = await RMQ_INSTANCE.getInstance();
      var channel = await connection.createChannel();
      var exchange = 'some_exchange';
      var key = 'some_key';
      var msg = JSON.stringify(message);
      await channel.assertExchange(exchange, 'topic', { durable: false });
      await channel.publish(exchange, key, Buffer.from(msg));
      setTimeout(function () {
        connection.close();
      }, 500);
    };
    

    a.js:

    class RMQ {
      constructor(connectionURI) {
        this.URI = connectionURI;
      }
      async getInstance() {}
    }
    
    const RMQ_INSTANCE = new RMQ(process.env.RMQ_URL);
    
    module.exports = { RMQ_INSTANCE };
    

    b.test.js:

    const sinon = require('sinon');
    const { RMQ_INSTANCE } = require('./a');
    const { publishEmail } = require('./b');
    
    describe('test_producer', () => {
      let clock;
      before(() => {
        clock = sinon.useFakeTimers();
      });
      after(() => {
        clock.restore();
      });
      it('producer connection - success test', async () => {
        const channelStub = {
          assertExchange: sinon.stub().returnsThis(),
          publish: sinon.stub(),
        };
        const connectionStub = { createChannel: sinon.stub().resolves(channelStub), close: sinon.stub() };
        sinon.stub(RMQ_INSTANCE, 'getInstance').resolves(connectionStub);
        await publishEmail('fake message');
        sinon.assert.calledOnce(RMQ_INSTANCE.getInstance);
        sinon.assert.calledOnce(connectionStub.createChannel);
        sinon.assert.calledWithExactly(channelStub.assertExchange, 'some_exchange', 'topic', { durable: false });
        sinon.assert.calledWithExactly(
          channelStub.publish,
          'some_exchange',
          'some_key',
          Buffer.from(JSON.stringify('fake message')),
        );
        clock.tick(500);
        sinon.assert.calledOnce(connectionStub.close);
      });
    });
    

    测试结果:

      test_producer
        ✓ producer connection - success test
    
    
      1 passing (10ms)
    
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------|---------|----------|---------|---------|-------------------
    All files |     100 |      100 |      75 |     100 |                   
     a.js     |     100 |      100 |      50 |     100 |                   
     b.js     |     100 |      100 |     100 |     100 |                   
    ----------|---------|----------|---------|---------|-------------------
    

    【讨论】:

    • 非常感谢您的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-06
    • 1970-01-01
    • 2020-11-07
    • 1970-01-01
    • 1970-01-01
    • 2017-10-17
    • 2020-05-28
    相关资源
    最近更新 更多