无法使用Sinon存根函数

时间:2017-09-22 09:49:05

标签: javascript redux sinon

我有一个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:[功能:functionB]不是间谍或对间谍的调用!

当我将功能输出到控制台时,我得到了这个,这似乎与Babel导入导出导出的方式有关  (ES6 re-exported values are wrapped into Getter)。这些功能可以正常工作,而不是在测试中。

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

我已尝试使用stub.get(getterFn),但这只是给了我错误:

  

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

2 个答案:

答案 0 :(得分:0)

您是否尝试过命名存根?你的代码读起来有点奇怪。在测试的任何时候,你都没有提到你的存根。

def publish
  @post = Post.find(params[:id])
  authorize @post, :update?
  @post.publish!
  redirect_to @post
end

答案 1 :(得分:0)

很难说是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的引用,这将使您可以用存根替换它们。

如果您发现总体问题并希望保留原始格式,那么我认为您需要使用另一个名为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才会导入,它将使用存根模块而不是实际模块。

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