什么是正确的嘲笑下面的示例中的最佳方式是什么?
问题是,进口时间后,foo
保持参照原unmocked bar
。
module.js:
export function bar () {
return 'bar';
}
export function foo () {
return `I am foo. bar is ${bar()}`;
}
module.test.js:
import * as module from '../src/module';
describe('module', () => {
let barSpy;
beforeEach(() => {
barSpy = jest.spyOn(
module,
'bar'
).mockImplementation(jest.fn());
});
afterEach(() => {
barSpy.mockRestore();
});
it('foo', () => {
console.log(jest.isMockFunction(module.bar)); // outputs true
module.bar.mockReturnValue('fake bar');
console.log(module.bar()); // outputs 'fake bar';
expect(module.foo()).toEqual('I am foo. bar is fake bar');
/**
* does not work! we get the following:
*
* Expected value to equal:
* "I am foo. bar is fake bar"
* Received:
* "I am foo. bar is bar"
*/
});
});
谢谢!
编辑:我可以改变:
export function foo () {
return `I am foo. bar is ${bar()}`;
}
至
export function foo () {
return `I am foo. bar is ${exports.bar()}`;
}
但是这是对P。丑陋在我看来的确无处不在:/
这个问题似乎涉及您如何期待吧的范围加以解决。
一方面,在module.js
导出两个函数(代替的物体保持这两个函数)。由于路模块输出的参考的出口事物的容器exports
像你提到它。
在另一方面,你处理你的出口(您化名module
)一样的物体保持这些功能,并试图取代它的功能之一(功能栏)。
如果您在您的富落实仔细观察你实际上是拿着固定的参考吧的功能。
当你认为你有更换一个新的酒吧功能,您只需更换实际参考副本在你module.test.js范围
为了使FOO实际使用酒吧的另一个版本,有两种可能性:
export class MyModule {
function bar () {
return 'bar';
}
function foo () {
return `I am foo. bar is ${this.bar()}`;
}
}
注意在foo的方法使用该关键字。
Module.test.js:
import { MyModule } from '../src/module'
describe('MyModule', () => {
//System under test :
const sut:MyModule = new MyModule();
let barSpy;
beforeEach(() => {
barSpy = jest.spyOn(
sut,
'bar'
).mockImplementation(jest.fn());
});
afterEach(() => {
barSpy.mockRestore();
});
it('foo', () => {
sut.bar.mockReturnValue('fake bar');
expect(sut.foo()).toEqual('I am foo. bar is fake bar');
});
});
exports
容器中的全球基准。这是不要去,你很可能会在其他测试中引入怪异的行为,如果你没有正确地重置出口到初始状态的推荐方式。另一种解决方案可以导入模块插入它自己的代码文件,并使用所有导出的实体的进口情况。像这样:
import * as thisModule from './module';
export function bar () {
return 'bar';
}
export function foo () {
return `I am foo. bar is ${thisModule.bar()}`;
}
现在嘲讽bar
是很容易的,因为foo
还使用bar
的出口情况:
import * as module from '../src/module';
describe('module', () => {
it('foo', () => {
spyOn(module, 'bar').and.returnValue('fake bar');
expect(module.foo()).toEqual('I am foo. bar is fake bar');
});
});
导入模块插入它自己的代码看起来很奇怪,但由于ES6对循环进口的支持,它的作品真的顺利。
FWIW,我看中了是使用dependency injection,通过设置默认参数的解决方案。
所以,我会改变
export function bar () {
return 'bar';
}
export function foo () {
return `I am foo. bar is ${bar()}`;
}
至
export function bar () {
return 'bar';
}
export function foo (_bar = bar) {
return `I am foo. bar is ${_bar()}`;
}
这并不是我的组件的API重大更改,我可以很容易地通过执行以下操作覆盖在我的测试吧
import { foo, bar } from '../src/module';
describe('module', () => {
it('foo', () => {
const dummyBar = jest.fn().mockReturnValue('fake bar');
expect(foo(dummyBar)).toEqual('I am foo. bar is fake bar');
});
});
这有导致轻微更好的测试代码的好处太:)
我有这个同样的问题,由于该项目的掉毛标准,定义一个类或改写在exports
引用没有代码审查,即使不掉毛定义防止可批准的选项。我无意中发现了一个可行的办法是使用babel-rewire-plugin这是干净多了,至少在外表。当我发现这在另一个项目中,我不得不使用的访问,我发现它已经在我所挂here类似的问题的答案。这是从参考链接的答案提供调整这个问题(和不使用间谍)摘要(我还添加了除分号去除间谍,因为我不是一个异教徒):
import __RewireAPI__, * as module from '../module';
describe('foo', () => {
it('calls bar', () => {
const barMock = jest.fn();
__RewireAPI__.__Rewire__('bar', barMock);
module.foo();
expect(bar).toHaveBeenCalledTimes(1);
});
});
如果你定义的出口之后就可以引用你的功能部分的出口对象。然后你就可以在你的嘲笑个别覆盖的功能。这是由于进口的工作方式作为参考,而不是副本。
module.js:
exports.bar () => {
return 'bar';
}
exports.foo () => {
return `I am foo. bar is ${exports.bar()}`;
}
module.test.js:
describe('MyModule', () => {
it('foo', () => {
let module = require('./module')
module.bar = jest.fn(()=>{return 'fake bar'})
expect(module.foo()).toEqual('I am foo. bar is fake bar');
});
})
对我的作品:
cat moduleWithFunc.ts
export function funcA() {
return export.funcB();
}
export function funcB() {
return false;
}
cat moduleWithFunc.test.ts
import * as module from './moduleWithFunc';
describe('testFunc', () => {
beforeEach(() => {
jest.clearAllMocks();
});
afterEach(() => {
module.funcB.mockRestore();
});
it.only('testCase', () => {
// arrange
jest.spyOn(module, 'funcB').mockImplementationOnce(jest.fn().mockReturnValue(true));
// act
const result = module.funcA();
// assert
expect(result).toEqual(true);
expect(module.funcB).toHaveBeenCalledTimes(1);
});
});