当前位置: 首页 > 知识库问答 >
问题:

无法使用Sinon存根函数

郝玄天
2023-03-14

我有一个Redux操作,它本身分派了另外两个操作。每个操作都是从导入的函数中检索的。一个来自本地模块,另一个来自外部库。

import { functionA } from './moduleA';
import { functionB } from 'libraryB';

export function myAction() {
  return (dispatch) => {
    dispatch(functionA());
    ...
    dispatch(functionB());
  }
}

在我的测试中,我使用一个 sinon 沙箱来存根函数,但只有两个测试通过。我期待所有3个都通过。

import * as A from './moduleA';
import * as B from 'libraryB';

describe(__filename, async () => {
  it('Calls 2 other actions', () => {
    sandbox = sinon.sandbox.create();

    const dispatch = sandbox.stub();

    sandbox.stub(A, 'functionA');
    sandbox.stub(B, 'functionB');

    await myAction()(dispatch);

    // passes
    expect(dispatch.callCount).to.equal(2);

    //passes
    expect(A.functionA).to.have.been.called();

    // fails
    expect(B.functionB).to.have.been.called();     
  });
});

最后一个预期失败,错误为:

TypeError:[Function:functionB]不是间谍或对间谍的调用!

当我将功能输出到控制台时,我得到了这个,这似乎与Babel导入导出导出的方式有关(ES6重新导出的值被包装到Getter中)。这些功能可以实时工作,只是在测试中没有。

{ functionA: [Function: functionA] }
{ functionB: [Getter] }

我试过使用stub.get(getterFn),但这只给我错误:

TypeError:无法重新定义属性:fetchTopicAnnoations

共有2个答案

龚承嗣
2023-03-14

很难说100%,但似乎模块正在导入,因此在您的测试存根之前直接引用了该函数。Sinon将有效地替换导出对象上的函数,但另一个模块将首先导入并获得对真实函数的引用,替换它不会导致它重新加载。

您可以进行试验,并通过将您的模块修改为以下形式来证明这一点:

import * as A from './moduleA';
import * as B from 'libraryB';

export function myAction() {
  return (dispatch) => {
    dispatch(A.functionA());
    ...
    dispatch(B.functionB());
  }
}

这将在调用时查找对functionA/functionB的引用,这将允许sining用存根替换它们。

如果您觉得很恶心并想保留原始形式,那么我相信您需要使用名为proxyquire的第二个库,这将有效地让您存根正在导入的整个模块。

您的测试函数最终看起来更像这样:

import * as proxyquire from 'proxyquire'
// import * as A from './moduleA'
// import * as B from 'libraryB'

describe(__filename, async () => {
  const A = {}
  const B = {}
  const functionAStub = sandbox.stub(A, 'functionA')
  const functionBStub = sandbox.stub(B, 'functionB')
  const { myAction } = proxyquire('./myAction', {
    './moduleA': A,
    'libraryB': B
  })
  ...
})

在调用 proxyquire 时,不会导入受测模块,否则将使用存根模块而不是实际模块。

然后,您可以按预期从测试中引用这些存根。

慕兴平
2023-03-14

你试过给你的存根命名吗?你的代码读起来有点奇怪。你在考试的任何时候都没有提到你的存根。

import * as A from './moduleA';
import * as B from 'libraryB';

describe(__filename, async () => {
  it('Calls 2 other actions', () => {
    sandbox = sinon.sandbox.create();

    const dispatch = sandbox.stub();

    const functionAStub = sandbox.stub(A, 'functionA');
    const functionBStub = sandbox.stub(B, 'functionB');

    await myAction()(dispatch);

    // passes
    expect(dispatch.callCount).to.equal(2);

    //passes
    expect(functionAStub.called).toBe(true);

    // fails
    expect(functionBStub.called).toBe(true);     
  });
});
 类似资料:
  • 我有一个带有路由器的express应用程序,我想与Sinon一起测试。我无法成功模拟传递到请求处理程序的参数,希望能得到一些帮助。 这是我当前使用Mocha、Sinon、Chai的测试设置

  • 问题内容: 我希望对我当前正在测试的文件中使用的函数存根。像这样的解构需要此函数: 测试时,永远不会调用存根,而是继续调用实函数。但是当我“正常”地要求它时(即:不破坏结构) 然后正确使用存根,一切正常 我感觉这是因为解构的工作原理以及直接对对象属性而不是对函数进行存根的事实。无论如何,如果您能为我提供一些见解,我将不胜感激! 问题答案: 使用从从属模块进行解构时,对模块的方法进行插桩的原因很简单

  • 我在获取一个sinon存根以返回/解析另一个sinon存根时遇到问题。我正在使用西农、柴、柴和摩卡。 我正在按顺序执行许多异步任务,我想测试的代码看起来像这样: 我尝试为此创建存根的尝试如下所示: “saveit”方法在Terminal.prototype,这就是为什么我需要在那里存根它。当我尝试运行它时,我收到错误消息: 在线上: 但如果我在控制台中转储终端对象,它看起来很好,就像任何其他存根对

  • 我希望在当前测试的文件中存根一个函数。此函数在进行如下分解时是必需的: 在测试时,永远不会调用存根,而是继续调用实际函数。但当我“正常”需要它时(即:不进行分解) 然后正确使用存根,一切正常 我感觉到这是因为析构是如何工作的,事实上存根是对象属性,而不是直接的函数。无论如何,如果你能给我提供一些见解,我将不胜感激!

  • 我有一个redux操作,它有一个对API的异步调用。 我试图通过使用sinon存根来模拟fetchActionCreator方法。这是我的规范文件 但不知何故,这个函数并没有受到嘲弄。你能告诉我正确的方法吗。

  • 我试图为express中间件功能设置存根伪造,但它并没有被取代。 我正试图通过callsFake函数使用sinon stubbing,正如他们最新文档中建议的那样。 即使我需要模块并在导出时替换属性中的函数。我一直看到原来的函数行为在起作用。 我知道我应该在安装中间件函数之前尝试将函数存根,而这正是第一次导入express的时候。 这是我尝试存根的函数,定义为函数并导出为对象。它在脚本文件中定义,