【问题标题】:sinon spy on standalone functionsinon spy on 独立功能
【发布时间】:2015-11-26 01:44:28
【问题描述】:

当我在对象内部的函数上使用 Sinon 时,它可以工作:

function myFunc() {
    console.log('hello');
}
var myObj = { myFunc: myFunc };
var spy = sinon.stub(myFunc);
myObj.myFunc();
expect(spy.called).to.be.true(); 

但是,当我在独立功能上使用 Sinon 时,我不知道为什么:

function myFunc() {
    console.log('hello');
}
var spy = sinon.stub(myFunc);
myFunc();
expect(spy.called).to.be.true(); 

断言失败。

【问题讨论】:

  • 我也遇到了同样的问题,这个话题有更新吗?
  • 监视独立功能时仍然无法正常工作

标签: sinon


【解决方案1】:

您的第一个示例效果不佳。目前无法从独立函数创建存根。您可以存根对象的方法:

var stub = sinon.stub(myObj, 'myFunc');

但是如果你想监视方法或函数,你应该创建一个spy(而不是存根):

窥探方法:

var spy = sinon.spy(myObj, 'myFunc');
myObj.myFunc(); // or spy();
expect(spy.called).to.be.true(); 

监视独立功能:

var spy = sinon.spy(myFunc); // returns spied function
spy();
expect(spyFunc.called).to.be.true();

注意sinon.spy(myFunc) 不会修改原始函数,它只是返回一个间谍。

【讨论】:

  • 这实际上是一个非常糟糕的答案,因为 OP 显然不想使用 sinon 的间谍。 OP 想要监视独立功能。 Sinon spy() 创建函数。它不会监视其他功能。
【解决方案2】:

我不确定浏览器端是否有解决方案。

但是如果你在node.js环境中运行,你可以导出函数并在另一个文件中测试。

比如你的源文件是source.js,测试文件是test.js

在 source.js 中

function myFunc() {
    console.log('hello');
}
module.exports.myFunc = myFunc;

在 test.js 中

var source = require('./source');
var sinon = require('sinon');
var expect = require('chai').expect;

sinon.stub(source, 'myFunc').returns(true);
source.myFunc();
expect(sinon).to.be.true;

希望对你有帮助。

【讨论】:

  • 上面的代码在大多数情况下都不起作用。 Sinon 不能存根独立函数。您真正要做的是将函数导出为对象。从诗乃看到这个:github.com/sinonjs/sinon/issues/664
  • 我遇到了一个问题,我使用导入而不是要求,并且我无法存根。当我在这个答案中看到它使用 require 而不是 import 时,它起作用了。此外,如果您正在处理函数的默认导出,那么您再次希望使用 require 而不是 import,并且您还需要对函数名称“default”而不是实际函数名称进行存根。 const myexportedfunction = require('./source'); let mystub = sinon.stub(myexportedfunction, "default");
【解决方案3】:

有点在正确的道路上,但偏离了方向。让我们逐步完成您的工作并把事情做好:

// ...
function myFunc() {
    console.log( 'hello' );
}
var spiedMyFunc = sinon.spy( myFunc ); // what you want is a 'spy' not a 'stub'
// ...

然后在这一点上spiedMyFunc 包裹myFunc。因此,调用spiedMyFunc() 应该在很大程度上相当于与调用myFunc() 的结果相同。同时spiedMyFunc另外

记录所有参数、这个值、异常和返回值 来电。

所以剩下的sn-p代码应该如下:

// myFunc(); // no you should be calling spiedMyFunc() instead
spiedMyFunc();
expect( spiedMyFunc.called ).to.be.true();

这就是您监视独立函数的方式。但是,存根独立函数在概念上没有意义


在对此答案的评论中回答@charlesdeb 的问题:

当一个方法被调用时,它可以触发一个隐式调用其他方法的链。由于这种隐式或间接调用,您可能希望控制链中其他方法的行为,同时研究特定方法的行为。 存根是实现上述控制的一种手段。

在使用函数时,实际上遵循函数范式以使事情变得简单可靠是有益的。考虑一下:

function a () { ... }

function b () { a(); }

在测试b时,证明b()的执行依次执行a()是必要且充分的。但是以b的实现方式,无法验证是否调用了a

但是,如果我们应用函数范式,那么我们应该有

function a () { ... }

function b ( a ) { a(); }

因此我们可以编写一个简单的测试如下:

var a_spy = sinon.spy( a );

var actualOutcomeOfCallingB = b( a_spy );

expect( a_spy.called ).to.be.true;
expect( actualOutcomeOfCallingB ).to.equal( expectedOutcome );

如果您想存根a,那么不要使用真正的a 创建间谍,而是使用您喜欢的存根。

var a_stub = sinon.spy( function () { /* behaves differently than the actual `a` */ }  ); // that's your stub right there!

var actualOutcomeOfCallingB = b( a_stub );

expect( a_stub.called ).to.be.true;
expect( actualOutcomeOfCallingB ).to.equal( expectedOutcome );

【讨论】:

  • 感谢整理 OP 的逻辑。我遵循第一个代码块,但最后你说:“存根独立函数在概念上没有意义。”为什么不?并非我的代码中的所有函数都属于对象。有些确实是独立的,我想测试它们,而不必将它们附加到某个容纳所有的对象。我真的很想看看 myFunc() 是否在被测代码中被调用。 spiedMyFunc() 在我的源代码中不存在 - 当然永远不会被调用。
  • @charlesdeb,我已通过编辑我的答案来回答您的问题。检查我更新的答案..
  • 非常感谢您的意见。你说除非你应用函数范式并将'a'作为'b'中的参数之一,否则“不可能验证a被调用”。这只是对独立功能的某种 sinon 限制吗?我会认为在设置“a_spy”之后,无论在哪里以及如何调用“a”,我都可以通过检查“a_spy”来测试这些调用。它似乎对非独立功能这样做。也许我在这里错过了什么!
  • 我有一个想法可以为您最终澄清问题:您如何创建一个应该测试的假设源代码并围绕它构建您的问题,我们可以一起分析挑战?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-17
  • 2017-09-19
  • 1970-01-01
相关资源
最近更新 更多