首页 > 解决方案 > 如何模拟/传递使用 mocha-chai-sinon 在其中执行函数的 Nodejs 辅助实用程序

问题描述

假设我有一个如下文件:

src/blah.js

var Foo = require("../../something/foo.js");

var goo = new Foo({
  host: argv.host.toString(),
  port: parseInt(argv.port)
});
goo.order("service_name");
goo.do("invalidPhone", function(req, done) {
  goo.talk('newFunc', 'newAct', req.data, function(newActErr, newActResponse){
       done(newActResponse)
  })
});

exports.goo = goo;

其中“something/foo.js”是执行各种功能的实用程序助手项目。假设goo.order在某处注册 service_name 并使用函数名goo.do实际执行一些工作。invalidPhone

在这种情况下,其他一些服务会invalidPhone使用一些参数调用该函数req。当invalidPhone函数被调用时,该函数应该打印“Here!” 连同进来的任何东西req.data

无论如何我要为功能编写一个单元测试用例invalidPhone吗?我假设要实现我需要以某种方式模拟goo.do(),但我该怎么做呢?

我尝试编写如下测试用例:

var eventService = require("../src/blah");
var base = eventService.goo;
var sinon = require("sinon");

describe("Goo Blah service", function(done) {
  beforeEach(function() {
    this.consoleSpy = sinon.spy(console, "log");
  });

  afterEach(function() {
    this.consoleSpy.restore();
  });

  it("Response should be logged", function() {
    goo.action("invalidPhone", "a123456789");
    this.consoleSpy.called.should.be.true;
  });
});

但上面的方法似乎不起作用。

编辑1:如果我的代码如下所示,并且我有一个新函数goo.talk来模拟/存根并在newActErrand中返回一些值newActResp怎么办?值newFuncnewAct可以改变。那我该怎么做呢?

var Foo = require("../../something/foo.js");

var goo = new Foo({
  host: argv.host.toString(),
  port: parseInt(argv.port)
});
goo.order("service_name");
goo.do("invalidPhone", function(req, done) {
  goo.talk('newFunc', 'newAct', req.data, function(newActErr, newActResponse){
       if(newActResponse.status){
          done(null, newActResponse)
       } else {
          done('error', null)
       }

  })
});

exports.goo = goo;

按照 deerawan 提供的答案提示/帮助,我尝试了以下方法:

talkStub = sinon.stub().withArgs('newFunc', 'newAct', {data: "name"}).returns({"status":"online"})

标签: node.jsunit-testingmocha.jssinonchai

解决方案


您的测试无法进行,因为您在文件开头console.log加载源文件后进行了模拟/间谍活动blah

var eventService = require("../src/blah");

Foo除此之外,如果您可以模拟该类以使测试变得孤立,那也更好。

我建议用来proxyquire帮助做这些事情。Proxyquirerequire但也可以对源文件中的任何依赖项进行一些模拟。

看看下面的解决方案:

const chai = require('chai');
const proxyquire = require('proxyquire');
const sinon = require('sinon');

// need to specify this so Foo constructor can be initialized
process.argv.host = 'http';
process.argv.port = '333';

describe("Goo Blah service", function() {
  let consoleSpy;
  let orderStub;
  let doStub;

  beforeEach(function() {
    orderStub = sinon.stub();
    doStub = sinon.stub().yields({ data: 'mine' });

    // this our mock for Foo class
    function MockFoo() {
      return {
        order: orderStub,
        do: doStub,
      }  
    }

    consoleSpy = sinon.spy(console, 'log');

    // require the source file and mock `foo`
    proxyquire('../src/blah', { '../../something/foo.js': MockFoo } );
  });

  afterEach(function() {
    sinon.restore();
  });

  it("Response should be logged", function() {
    sinon.assert.calledWith(orderStub, 'service_name');
    sinon.assert.calledWith(doStub, 'invalidPhone');

    sinon.assert.called(consoleSpy);
    sinon.assert.calledWith(consoleSpy, 'Here!', 'mine');
  });
});

希望能帮助到你


推荐阅读