简体   繁体   English

无法使用Sinon存根函数

[英]Unable to stub a function using Sinon

I have a Redux action, which itself dispatches two other actions. 我有一个Redux动作,它本身会调度其他两个动作。 Each action is retrieved from an imported function. 每个操作均从导入的函数中检索。 One from a local module, the other from an external library. 一个来自本地模块,另一个来自外部库。

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

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

In my tests I'm using a sinon sandbox to stub out the functions but only two of the tests pass. 在我的测试中,我使用sinon沙箱对功能进行了测试,但是只有两个测试通过了。 I'm expecting all 3 to pass. 我希望所有三个都通过。

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();     
  });
});

The last expect fails with the error: 最后的期望因错误而失败:

TypeError: [Function: functionB] is not a spy or a call to a spy! TypeError:[Function:functionB]不是间谍,也不是间谍!

When I output the functions to the console I get this, which seems to be related to the way Babel imports an exported export ( ES6 re-exported values are wrapped into Getter ). 当我将功能输出到控制台时,我得到了这一点,这似乎与Babel导入导出导出的方式有关(将ES6重新导出的值包装到Getter中 )。 The functions work live, just not in the test. 这些功能可以实时运行,只是不在测试中。

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

I've tried using stub.get(getterFn) but that just gives me the error: 我试过使用stub.get(getterFn)但这只是给我错误:

TypeError: Cannot redefine property: fetchTopicAnnotations TypeError:无法重新定义属性:fetchTopicAnnotations

Have you tried naming your stubs? 您是否尝试过命名存根? Your code reads a bit weird. 您的代码有点怪异。 You're not referring to your stubs at any point in your test. 在测试中的任何时候,您都不是指存根。

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);     
  });
});

Its hard to say 100% but it appears that the module is importing and therefore has a direct reference to the function before your test is stubbing. 很难说是100%,但是看来该模块正在导入,因此在进行测试存根之前直接引用了该功能。 Sinon will effectively replace the function on the exports object but the other module will have imported and gotten a reference to real function first, replacing it won't cause it to reload. Sinon将有效地替换导出对象上的函数,但另一个模块将首先导入并获得对实函数的引用,替换它不会导致重新加载。

You could experiment with it and prove it by altering your module to be this: 您可以对其进行试验并通过将其更改为以下模块来证明这一点:

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

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

That will essentially look up the reference to functionA/functionB at the time of invocation which will allow sining to replace them with a stub. 从本质上讲,这将在调用时查找对functionA / functionB的引用,这将使您可以用存根替换它们。

If you find that gross and want to preserve the original form then I believe you need to use a second library called proxyquire , which will effectively let you stub the entire module being imported. 如果您发现这很重要,并且想要保留原始格式,那么我相信您需要使用另一个名为proxyquire库,它将有效地使您存根要导入的整个模块。

Your test functions would end up looking more like this: 您的测试功能最终看起来像这样:

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
  })
  ...
})

The module under test will not be imported until you call proxyquire when it is require'ing the module it will use your stubbed modules instead of the real ones. 在需要该模块时,直到您调用proxyquire时,该模块才会被导入,它将使用存根模块而不是真实模块。

You can then reference those stubs from within your tests as expected. 然后,您可以按预期从测试中引用这些存根。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM