Sinon存根函数用于解构

Suf*_*ane 7 unit-testing node.js sinon

我希望对当前正在测试的文件中使用的函数存根。像这样的解构需要此函数:

 const { theFunctionIWant } = require('path/to/module')
Run Code Online (Sandbox Code Playgroud)

测试时,永远不会调用存根,而是继续调用实函数。但是当我“正常”地要求它时(即:不破坏结构)

const myModule = require('path/to/module')
Run Code Online (Sandbox Code Playgroud)

然后正确使用存根,一切正常

我认为这是由于解构的工作原理以及sinon直接对对象属性而不是对函数进行存根的事实。无论如何,如果您能为我提供一些见解,我将不胜感激!

oli*_*ren 15

使用从从属模块进行解构时,对模块方法进行存根处理的原因非常简单,并且与绑定实际函数引用的时间有关。它与CommonJS模块,Sinn或Node本身没有任何关系,因此我将以简单的JavaScript示例开始。

const stub = (o, method) => (o[method] = () => "I am a stub");

const obj = {
  methodFoo() {
    return "I am foo";
  }
};

// same as doing `const methodFoo = obj.methodFoo;`
const { methodFoo } = obj; // "import" using destructuring

console.log("obj.methodFoo(): ", obj.methodFoo());
console.log("methodFoo()", methodFoo());

console.log("Stubbing out method!");
stub(obj, "methodFoo");

console.log("obj.methodFoo: ", obj.methodFoo());
console.log("methodFoo()", methodFoo());
Run Code Online (Sandbox Code Playgroud)

如果您运行上述示例,即使您已经将 methodFooobj“模块”属性进行了,直接绑定的引用仍会返回旧值!

这是因为,在存根时,您实际上是在向对象的属性(此处为obj)分配一个新值(一个函数)。对此新值的新引用(使用obj.methodFoo)将打印新值, 但是如果您存储了对旧函数的引用,则在调用旧函数时仍将获得旧的返回值。

同样适用于您的原始问题。如果您在模块A中依赖foo于模块B中的功能并存储该引用,则是否为导出的值分配新值(例如存根)都没有关系,因为您已经存储了对B的引用。旧值。

在本质上:

这将受到存根的影响

const A = require('./A');

function doFoo(){
    A.foo(); // will always evalute  A['foo']()
}
Run Code Online (Sandbox Code Playgroud)

这不会受到存根的影响

const myFoo = require('./A').foo;

function doFoo(){
    myFoo(); // will just evalute to the original value of A.foo()
}
Run Code Online (Sandbox Code Playgroud)

  • @oligofren 非常好的解释。那么,有没有解决方案可以在使用“析构函数”时预测原始函数的执行呢? (2认同)
  • 从我对你的问题的理解来看,不,不是单独使用诗乃。您需要一些与模块的实际加载挂钩并替换它的东西,以及如何配置取决于您的环境(纯 Node、Browserify、Webpack 等)。示例:`rewire` 或 `proxyquire`。有关示例,请参见 sinonjs.org/how-to。 (2认同)