[英]How to stub exported function in ES6?
我有文件 foo.js:
export function bar (m) {
console.log(m);
}
另一个使用 foo.js 的文件 cap.js:
import { bar } from 'foo';
export default m => {
// Some logic that I need to test
bar(m);
}
我有 test.js:
import cap from 'cap'
describe('cap', () => {
it('should bar', () => {
cap('some');
});
});
不知何故,我需要在测试中覆盖bar(m)
实现。 有没有办法做到这一点?
PS 我使用 babel、webpack 和 mocha。
哎哟..我找到了解决方案,所以我使用sinon
存根并import * as foo from 'foo'
以获取具有所有导出函数的对象,以便我可以存根它们。
import sinon from 'sinon';
import cap from 'cap';
import * as foo from 'foo';
sinon.stub(foo, 'bar', m => {
console.log('confirm', m);
});
describe('cap', () => {
it('should bar', () => {
cap('some');
});
});
您只能从模块本身内部替换/重写/存根导出。 (这里有一个解释)
如果你像这样重写'foo.js':
var bar = function bar (m) {
console.log(m);
};
export {bar}
export function stub($stub) {
bar = $stub;
}
然后,您可以像这样在测试中覆盖它:
import cap from 'cap'
import {stub} from 'foo'
describe('cap', () => {
it('should bar', () => {
stub(() => console.log('stubbed'));
cap('some'); // will output 'stubbed' in the console instead of 'some'
});
});
我创建了一个 Babel 插件,可以自动转换所有导出,以便它们可以被存根: https : //github.com/asapach/babel-plugin-rewire-exports
虽然@Mike 解决方案适用于旧版本的 sinon,但它已从 sinon 3.0.0 中删除。
现在代替:
sinon.stub(obj, "meth", fn);
你应该做:
stub(obj, 'meth').callsFake(fn)
模拟 google oauth api 的示例:
import google from 'googleapis';
const oauth2Stub = sinon.stub();
sinon.stub(google, 'oauth2').callsFake(oauth2Stub);
oauth2Stub.withArgs('v2').returns({
tokeninfo: (accessToken, params, callback) => {
callback(null, { email: 'poo@bar.com' }); // callback with expected result
}
});
你可以使用babel-plugin-rewire ( npm install --save-dev babel-plugin-rewire
)
然后在test.js
使用导入模块上的__Rewire__
函数来替换该模块中的函数:
// test.js
import sinon from 'sinon'
import cap from 'cap'
describe('cap', () => {
it('should bar', () => {
const barStub = sinon.stub().returns(42);
cap.__Rewire__('bar', barStub); // <-- Magic happens here
cap('some');
expect(barStub.calledOnce).to.be.true;
});
});
一定要添加rewire
您的通天插件.babelrc
:
// .babelrc
{
"presets": [
"es2015"
],
"plugins": [],
"env": {
"test": {
"plugins": [
"rewire"
]
}
}
}
最后,正如您所看到的babel-plugin-rewire
插件仅在测试环境中启用,因此您应该调用测试运行程序并将BABEL_ENV
环境变量设置为test
(您可能已经这样做了):
env BABEL_ENV=test mocha --compilers js:babel-core/register test-example.js
注意:我无法让babel-plugin-rewire-exports
工作。
这对我来说也绝对是个难题......
我创建了一个小工具来解决 sinon 的这个限制。 (在js 中也可用)。
// mockable.ts 👇
import sinon from 'sinon' export function mockable<T extends unknown[], Ret>(fn: (...fnArgs: T) => Ret) { let mock: sinon.SinonStub<T, Ret> | undefined const wrapper = (...args: T) => { if (mock) return mock(...args) return fn(...args) } const restore = () => { mock = undefined } wrapper.mock = (customMock?: sinon.SinonStub<T, Ret>) => { mock = customMock || sinon.stub() return Object.assign(mock, { restore }) } wrapper.restore = restore return wrapper }
如果您将上述代码段粘贴到您的项目中,您可以像这样使用它
// foo.js
import { mockable } from './mockable'
// we now need to wrap the function we wish to mock
export const foo = mockable((x) => {
console.log(x)
})
// main.js
import { foo } from './foo'
export const main = () => {
foo('asdf') // use as normal
}
// test.js
import { foo } from './foo'
import { main } from './main'
// mock the function - optionally pass in your own mock
const mock = foo.mock()
// test the function
main()
console.assert(mock.calledOnceWith('asdf'), 'not called')
// restore the function
stub.restore()
这种方法的好处是您不必记住总是以某种方式导入函数。 import { foo } from './foo'
与import * as foo from './foo'
。 自动导入可能只适用于您的 IDE。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.