Sinon: 可以存根独立的实用程序函数吗?

创建于 2014-09-12  ·  18评论  ·  资料来源: sinonjs/sinon

许多节点模块将单个函数(不是构造函数,而是通用“实用程序”函数)导出为其“module.exports”。 是否可以使用 Sinon.js 来存根这个独立的函数?

// some module, "sum.js" that's "required" throughout the application
module.exports = function(a, b) {
    return a + b;
};

// test.js
var sum = require('sum');
...

beforeEach(function() {
    sumStub = sinon.stub(sum);
    // throws: TypeError: Attempted to wrap undefined property undefined as function
});

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

有没有办法实现这一目标?

最有用的评论

尝试这个

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

所有18条评论

不幸的是没有。

对于 npm,您可以使用https://github.com/thlorenz/proxyquire或类似方法。 Michael Feathers 将其称为链接接缝

这并不优雅,但可行。

一旦你有了它,你就可以像往常一样使用Sinon。

从长远来看,您可能希望将您的架构转向 _object 接缝_,但它是今天有效的解决方案。 RequireJS 也有类似的项目。

function MyFunction(){}
module.exports = function(){ return module.exports.MyFunction.apply(this, arguments) }
module.exports.MyFunction = MyFunction

然后您可以存根 require('./MyFunction').MyFunction 并且您的其余代码将无需更改即可查看存根版本。

:dizzy: :dizzy_face: :dizzy:

前几天偶然发现了同样的事情,这就是我所做的:

const proxyquire = require('proxyquire')
const sinon = require('sinon')
const sum = sinon.stub()

const ModuleWithDependency = proxyquire('module', {
  'sum': sum
})

对于我们的案例来说效果很好。

如果使用 CommonJS:

const myStubbedModule = function( absoluteModulePath ) {
  const stub = sinon.stub();
  require.cache[ require.resolve( absoluteModulePath ) ] = stub;
  return stub;
}

_注意_:根据您是否正在转译,您可能需要执行以下操作:

require.cache[ require.resolve( absoluteModulePath ) ] = {
  default: stub,
  exports: stub
}

通常在测试期间,我需要为一项特定测试插入一个存根。 我采用的包装函数方法让我可以随时修改代码库并插入我的存根,而不必采用存根优先的方法或使用引用其他模块的模块玩我正在尝试的模块存根和就地更换。

我已经进行了多次代码审查,人们通过 proxyquire、 mock-require和 c 推动我在 Node 模块层进行黑客攻击,它开始很简单,看起来不那么粗鲁,但成为获取存根的一个非常困难的挑战在测试设置期间需要到位。 使用 proxyquire 至少可以使用 proxyquire() 应用程序的微型/夹具大小版本,一些顶级的东西,并且所有存根都将在加载过程中被引入,但是在 JS 语言级别而不是 Node 模块级别继续解决这个问题让我觉得更直接,更容易持续管理且没有危险(警告:只要你记得恢复)。

我使这个模块更容易存根模块https://github.com/caiogondim/stubbable-decorator.js

我只是在玩 Sinon 并找到了似乎有效的简单解决方案 - 只需添加“参数”作为第二个参数

const sumStub = sinon.stub(sum, 'arguments');
sumStub.withArgs(2, 2).returns(4);
sumStub.withArgs(3, 3).returns(6);

尝试这个

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

@harryi3t - 谢谢这对我

@harryi3t这对我不起作用,使用 ES 模块。
错误: can't redefine non-configurable property "default"

@elliottregan ES 模块根据标准不可存根。 我们甚至有涵盖这种行为的我在此处讨论的那样,您仍然可以这样做。

很多人实际上并不是在测试 ES 模块,而是转译了 ES 模块(使用 Webpack/Babel 等)。 生成的 ES5 使用 getter 来模拟 ES 模块的工作方式。 您可能正在这样做,但请尝试我在链接线程中建议的简单路线。 mocha --register ...会让你走得很远。

可能的解决方法

(function (defineProperty) {
    Object.defineProperty = (obj, prop, desc) => {
        desc.configurable = true;
        return defineProperty(obj, prop, desc);
    };
})(Object.defineProperty);

@Sujimoshi解决方法究竟是什么? 你修复的背景是什么? 另外,人们会把修复程序放在哪里? 在目前的版本中,它缺少的信息太多而无济于事。 它对原始问题没有帮助,也不适用于ES Modules 。 我猜它与 Webpack 4 处理过的代码有关,因为它可能适用于(取决于您的工具链)使用 ES2015+ 语法编写的代码,这些代码已_transpiled_ 到 ES5,_emulating_ES 模块通过不可配置的对象描述符的不变性.

尝试这个

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

现在已弃用。

我刚刚从这里重写了我的 ES6 模块:

export default const doCoolStuff = () => {
  // do the cool stuff...
}

对此:

export default {
  doCoolStuff: () => {
    // do the cool stuff...
  }
} 

它有点笨重,但使我能够将函数包装在存根中。

现在快2021年了,有可能吗?

现在快2021年了,有可能吗?

与2019年没有太大区别。
ES Modules 没变,CommonJS 没变,JavaScript 没变。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

zimtsui picture zimtsui  ·  3评论

brettz9 picture brettz9  ·  3评论

kbirger picture kbirger  ·  3评论

stephanwlee picture stephanwlee  ·  3评论

JakobJingleheimer picture JakobJingleheimer  ·  3评论