我有一个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:[功能:功能]不是间谍或对间谍的调用!
当我将函数输出到控制台时,我得到了这个,这似乎与Babel导入导出导出(ES6 re-exported values are wrapped into Getter)的方式有关。这些功能可以正常工作,而不是在测试中。
{ functionA: [Function: functionA] }
{ functionB: [Getter] }
我尝试过使用stub.get(getterFn)
,但这只是给了我错误:
TypeError:无法重新定义属性:fetchTopicAnnotations
你试过命名你的存根吗?你的代码读起来有点奇怪。在测试的任何时候,你都没有提到你的存根。
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);
});
});
很难说100%,但似乎模块正在导入,因此在测试存根之前直接引用该函数。 Sinon将有效地替换export对象上的函数,但是另一个模块将首先导入并获得对实际函数的引用,替换它不会导致它重新加载。
你可以试验它并通过改变你的模块来证明这一点:
import * as A from './moduleA';
import * as B from 'libraryB';
export function myAction() {
return (dispatch) => {
dispatch(A.functionA());
...
dispatch(B.functionB());
}
}
这将基本上在调用时查找对函数A /函数的引用,这将允许使用存根替换它们。
如果你发现它很糟糕并希望保留原始表单,那么我相信你需要使用第二个名为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
})
...
})
在您需要使用模块而不是真实模块的情况下调用代理查询时,才会导入被测模块。
然后,您可以按预期在测试中引用这些存根。