【问题标题】:How to mock a function in another function nodejs如何在另一个函数nodejs中模拟一个函数
【发布时间】:2019-04-19 20:37:42
【问题描述】:

尝试为 /utility/sqsThing.js 中的以下模块编写单元测试。但是我很难模拟 sqs.sendMessage 方法。任何人都知道我应该怎么做。我正在使用 sinon 库和 mocha 来运行测试。

我正在尝试对utility/sqsThing.js 进行单元测试的函数:

const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-1' });
const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
const outputQueURL = 'https:awsUrl';

const SQSOutputSender = (results) => {
  const params = {
    MessageBody: JSON.stringify(results),
    QueueUrl: outputQueURL,
  };
  // Method that I want to mock
  sqs.sendMessage(params, function (err, data) {
    if (err) {
      console.log('Error');
    } else {
      console.log('Success', data.MessageId);
    }
  });
};

我尝试在单元测试sqsThingTest.js 中模拟 sqs.sendMessage 方法:

const sqsOutputResultSender = require('../utility/sqsThing');
const AWS = require('aws-sdk');
const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });

const mochaccino = require('mochaccino');

const { expect } = mochaccino;
const sinon = require('sinon');


describe('SQS thing test', function() {
    beforeEach(function () {
        sinon.stub(sqs, 'sendMessage').callsFake( function() { return 'test' });
    });

    afterEach(function () {
        sqs.sendMessage.restore();
    });

  it('sqsOutputResultSender.SQSOutputSender', function() {
    // Where the mock substitution should occur
    const a = sqsOutputResultSender.SQSOutputSender('a');
    expect(a).toEqual('test');
  })
});

使用mocha tests/unit/sqsThingTest.js 运行这个单元测试但是我得到: AssertionError: expected undefined to deeply equal 'test'info: Error AccessDenied: Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied.

看起来模拟没有取代 aws api 调用。有人知道我如何在测试中模拟 sqs.SendMessage 吗?

【问题讨论】:

  • 试试 sinon.stub(sqs.prototype, 'sendMessage')
  • @JonathanNewton 尝试过sinon.stub(sqs.prototype, 'sendMessage').callsFake( function() { return 'test' })。这给了我这个错误:Error: Trying to stub property 'sendMessage' of undefined

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


【解决方案1】:

您可以使用rewire js,它是一个库,可让您将模拟属性注入您要测试的模块。

你的 require 语句看起来像这样:

var rewire = require("rewire");
var sqsOutputResultSender = rewire('../utility/sqsThing');

Rewire 将允许您在 sqsThing.js 文件的顶级范围内模拟所有内容。

您还需要返回sqs.sendMessage 的值,这将消除expected undefined to deeply equal 'test' 的问题

您的原始文件看起来与返回语句相同。

//utility/sqsThing.js
const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-1' });
const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
const outputQueURL = 'https:awsUrl';

const SQSOutputSender = (results) => {
  const params = {
    MessageBody: JSON.stringify(results),
    QueueUrl: outputQueURL,
  };
  // Method that I want to mock
  return sqs.sendMessage(params, function (err, data) {
    if (err) {
      console.log('Error');
    } else {
      console.log('Success', data.MessageId);
    }
  });
};

然后您将编写单元测试如下:

//sqsThingTest.js
var rewire = require("rewire");
var sqsOutputResultSender = rewire('../utility/sqsThing');
const mochaccino = require('mochaccino');
const { expect } = mochaccino;
const sinon = require('sinon');

describe('SQS thing test', function() {
    beforeEach(function () {
        sqsOutputResultSender.__set__("sqs", {
            sendMessage: function() { return 'test' }
        });
    });

  it('sqsOutputResultSender.SQSOutputSender', function() {
    // Where the mock substitution should occur
    const a = sqsOutputResultSender.SQSOutputSender('a');
    expect(a).toEqual('test');
  })
});

此示例返回一个属性为 sendMessage 的对象,但这可以替换为间谍。

Rewire Docs

【讨论】:

  • 为我工作。只需将myModule 更改为sqsOutputResultSender
  • @dredbound 已修复
【解决方案2】:

尝试在对sendmessage 函数进行存根后移动sqsOutputResultSender 的声明

    var sqsOutputResultSender;
    const AWS = require('aws-sdk');
    const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });

    const mochaccino = require('mochaccino');

    const { expect } = mochaccino;
    const sinon = require('sinon');


    describe('SQS thing test', function() {
        beforeEach(function () {
            sinon.stub(sqs, 'sendMessage').callsFake( function() { return 'test' });
            sqsOutputResultSender = require('../utility/sqsThing');
        });

        afterEach(function () {
            sqs.sendMessage.restore();
        });

      it('sqsOutputResultSender.SQSOutputSender', function() {
        // Where the mock substitution should occur
        const a = sqsOutputResultSender.SQSOutputSender('a');
        expect(a).toEqual('test');
      })
    });

【讨论】:

  • 不,仍然给我同样的AssertionError: expected undefined to deeply equal 'test'。和info: Error AccessDenied: Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied.
  • 您能否将调用移至另一个函数中的sqs.sendMessage
  • 我可以,但我仍然需要模拟它以便在我移动它的任何地方测试该功能。
  • 我不知道你为什么可以访问它,但这里有一个建议:Gist 然后你的存根看起来像这样 ` sinon.stub(sqsOutputResultSender, 'sendMessage').callsFake( function () { return 'test' });`
  • 运行仍然返回相同的AssertionError: expected undefined to deeply equal 'test'。它不是用存根替换函数。我怀疑我只是没有正确使用 sinon。
猜你喜欢
  • 1970-01-01
  • 2018-08-13
  • 2020-02-15
  • 2021-04-19
  • 1970-01-01
  • 2018-01-21
  • 1970-01-01
  • 2019-03-08
  • 2017-06-27
相关资源
最近更新 更多