【问题标题】:How to mock a constructor call in a node.js unit test?如何在 node.js 单元测试中模拟构造函数调用?
【发布时间】:2021-09-29 07:41:09
【问题描述】:

我编写了一个小的 node.js 模块来使用 Twit 库更新 twitter

// src/twitterHelper.js
const Twit = require('twit');
const twitterClient = new Twit({
  consumer_key: 'consumer_key',
  consumer_secret: 'consumer_secret',
  access_token: 'access_token',
  access_token_secret: 'access_token_secret',
});

function updateStatus(params, callback) {
  twitterClient.post('statuses/update', params, function (err, data, response) {
    if (err) {
      console.log(`Error occurred updating status\t${err}`);
    } else {
      console.log(`Posted twitter with id ${data.id_str}`);
    }
  });
}

exports.updateStatus = updateStatus;

我已经为此使用 mocha、chai 和 sinon 编写了一个单元测试。但是对 Twit 的构造函数的调用总是返回实际对象 - 我如何用单元测试中的模拟对象替换它?

// test/twitterHelper.spec.js
const Twit = require('twit')
const expect = require("chai").expect;
const sinon     = require('sinon');
const twitterHelper = require("../src/twitterHelper");

describe("Unit tests for twitter helper", () => {
    const mockTwit = {
        post: (endpoint, params, callback) => {
            console.log(`Called ${endpoint} with ${params}`);
        }
    };

    it("should create a mock twit object", () => { 
        sinon.stub(Twit, 'constructor').returns(mockTwit);
        twitterHelper.updateStatus({status: "New status"});
    });
});

【问题讨论】:

    标签: node.js unit-testing mocha.js chai sinon


    【解决方案1】:

    Sinon 不支持这样的类的存根构造函数。你需要使用Link Seams,这是CommonJS版本,所以我们将使用proxyquire来构造我们的接缝。

    例如

    twitterHelper.js:

    const Twit = require('twit');
    const twitterClient = new Twit({
      consumer_key: 'consumer_key',
      consumer_secret: 'consumer_secret',
      access_token: 'access_token',
      access_token_secret: 'access_token_secret',
    });
    
    function updateStatus(params, callback) {
      twitterClient.post('statuses/update', params, function (err, data, response) {
        if (err) {
          console.log(`Error occurred updating status\t${err}`);
        } else {
          console.log(`Posted twitter with id ${data.id_str}`);
        }
      });
    }
    
    exports.updateStatus = updateStatus;
    

    twitterHelper.test.js:

    const sinon = require('sinon');
    const proxyquire = require('proxyquire');
    
    describe('Unit tests for twitter helper', () => {
      it('should create a mock twit object', () => {
        const twitInstanceStub = { post: sinon.stub() };
        const TwitStub = sinon.stub().returns(twitInstanceStub);
        const twitterHelper = proxyquire('./twitterHelper', {
          twit: TwitStub,
        });
        twitterHelper.updateStatus({ status: 'New status' });
        sinon.assert.calledWithExactly(TwitStub, {
          consumer_key: 'consumer_key',
          consumer_secret: 'consumer_secret',
          access_token: 'access_token',
          access_token_secret: 'access_token_secret',
        });
        sinon.assert.calledWithExactly(
          twitInstanceStub.post,
          'statuses/update',
          { status: 'New status' },
          sinon.match.func,
        );
      });
    });
    

    测试结果:

      Unit tests for twitter helper
        ✓ should create a mock twit object (1506ms)
    
    
      1 passing (2s)
    
    ------------------|---------|----------|---------|---------|-------------------
    File              | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ------------------|---------|----------|---------|---------|-------------------
    All files         |   57.14 |        0 |      50 |   57.14 |                   
     twitterHelper.js |   57.14 |        0 |      50 |   57.14 | 11-14             
    ------------------|---------|----------|---------|---------|-------------------
    

    【讨论】:

      猜你喜欢
      • 2014-05-29
      • 1970-01-01
      • 2015-09-18
      • 1970-01-01
      • 2018-09-14
      • 2019-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多