如何 mock/pass 使用 mocha-chai-sinon 在其中执行函数的 Nodejs 辅助实用程序
How to mock/pass a Nodejs helper utility which executes functions in it using mocha-chai-sinon
假设我有如下文件:
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
作为函数名称执行了一些工作。
在这种情况下,某些其他服务使用某些参数 req
调用 invalidPhone
函数。当 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
到 mock/stub 和 return newActErr
和 [= 中的一些值怎么办? 26=]?值 newFunc
和 newAct
可以更改。那我该怎么做呢?
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 提供的答案 hint/help,我尝试了以下方法:
talkStub = sinon.stub().withArgs('newFunc', 'newAct', {data: "name"}).returns({"status":"online"})
您的测试无法进行,因为您在文件开头 blah
加载源文件 blah
console.log
mock/spy console.log
var eventService = require("../src/blah");
除此之外,如果您可以模拟 Foo
class 也更好,这样测试就变得孤立了。
我建议使用 proxyquire
来帮助完成这些工作。 Proxyquire
像 require
一样工作,但也可以对源文件中的任何依赖项进行一些模拟。
看看下面的解决方案:
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');
});
});
希望对您有所帮助
假设我有如下文件:
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
作为函数名称执行了一些工作。
在这种情况下,某些其他服务使用某些参数 req
调用 invalidPhone
函数。当 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
到 mock/stub 和 return newActErr
和 [= 中的一些值怎么办? 26=]?值 newFunc
和 newAct
可以更改。那我该怎么做呢?
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 提供的答案 hint/help,我尝试了以下方法:
talkStub = sinon.stub().withArgs('newFunc', 'newAct', {data: "name"}).returns({"status":"online"})
您的测试无法进行,因为您在文件开头 blah
加载源文件 blah
console.log
mock/spy console.log
var eventService = require("../src/blah");
除此之外,如果您可以模拟 Foo
class 也更好,这样测试就变得孤立了。
我建议使用 proxyquire
来帮助完成这些工作。 Proxyquire
像 require
一样工作,但也可以对源文件中的任何依赖项进行一些模拟。
看看下面的解决方案:
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');
});
});
希望对您有所帮助