node.js - 在 Node 中模拟构造函数

标签 node.js unit-testing testing tdd sinon

使用 sinon 的其他 Node 开发人员如何在他们的单元测试中模拟构造函数调用?例如,假设我有一些函数 foo

function foo() {
  var dependency = new Dependency(args);
  // do stuff with dependency
}
exports.module.foo = foo;

在一个单独的测试文件中,我有一些测试,我想在其中验证调用依赖构造函数的内容(args),并且我需要控制它返回的内容

it('should call Dependency constructor with bar', function() {
  var foo = require('myModule').foo
  var DependencyMock; //code to make the mock

  foo();
  expect(DependencyMock.calledWith(bar)).to.equal(true);
});

问题在于 sinon 只能模拟附加到对象的函数,因此我们必须先将构造函数附加到对象才能模拟。

我一直在做的只是制作一个对象,将构造函数附加到模块中,进行构造函数调用,将构造函数作为该对象的方法调用,然后导出对象以在测试中使用它:

var Dependency = require('path/to/dependency');

var namespace = {
  Dependency: Dependency
}

function foo() {
  var dependency = new namespace.Dependency(args);
  // do stuff with dependency
}
exports.moduole.foo = foo;
exports.module.namespace = namespace;

测试文件:

it('should call Dependency constructor with bar', function() {
  var foo = require('myModule').foo;
  var namespace = require('myModule').namespace;

  var DependencyMock = sinon.mock(namespace, 'Dependency').returns(0);
  foo();
  expect(DependencyMock.calledWith(bar)).to.equal(true);
});

这行得通,但是为了测试它而在我的模块上公开一个对象感觉真的很笨拙。

有什么建议吗?

最佳答案

我认为值得一问的是为什么要模拟依赖项的构造函数而不是注入(inject)该依赖项

考虑您的示例代码:

// in "foo.js"
function foo() {
  var dependency = new Dependency(args);
  // do stuff with dependency
}
exports.module.foo = foo;

如果 foo 需要 Dependency 才能工作,您可以将其作为 foo 的参数注入(inject):

// in "foo.js"
function foo(dependency) {
  // do stuff with dependency
}
exports.module.foo = foo;

// in "bar.js"
var foo = require('./foo.js')(new Dependency(args));

有了这个改变,在你的测试中注入(inject)任何测试替身现在变得微不足道了(要了解更多关于 JavaScript 测试替身的信息,请查看我的 article on the subject)。

这种方法使你的函数/模块的依赖关系显式化,但需要你在某个时候将它们连接起来(这里:require('./foo.js')(new Dependency(args));)。


如果您不想手动连接,还有另一种方法可以使用 rewirereplacing constructor with factory method :

// in "dependency.js"
module.exports= function(args) {
  return new Dependency(args);
}

// in "foo.js"
var dependency = require('./dependency');

function foo() {
  var dep = dependency(args);
  // do stuff with dependency
}
exports.module.foo = foo;

在你的测试中:

var rewire = require("rewire"),
    foo    = rewire("../lib/foo.js");

it('should call dependency... ', function() {
   foo.__set__("dependency", /* some spy */ );

   foo();
});

希望这对您有所帮助!

一月

关于node.js - 在 Node 中模拟构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33702588/

相关文章:

testing - 如何从 POSTMAN 集合导出到 JSON 获取 Karate 功能

unit-testing - API中的测试覆盖率

node.js - npm install 中没有 Elastic Beanstalk 依赖项?

javascript - Gulp.src() 的路径参数内的正则表达式

node.js - Mongo/Mongoose 检查项目是否存在

java - Java 中的单元测试缺少分支覆盖率

node.js - 两个nodejs服务器上的Access-Control-Allow-Origin错误

java - 在 1 个测试方法中使用 junit @Rule、expectMessage()、匹配器来处理多个异常

unit-testing - 是否有人真正成功地在整个团队中使用 MSTest?

python - 哪个更糟糕的设计 : sharing data between tests, 或每个测试的多个断言?