有什么办法可以用 Jest 模拟私有函数吗?
Is there any way to mock private functions with Jest?
我要测试的ES6模块如下所示:
function privateFunction() {
...
}
export function publicFunction() {
... does something ...
privateFunction()
... does something else ...
}
我正在使用 JEST 进行单元测试,我正在尝试找到一种方法来测试 publicFunction
并通过模拟它来避免执行 privateFunction
但我无法在模拟中成功试图。有什么想法吗?
JavaScript的本质是没有办法的。该函数被绑定到模块的范围内,因此无法从外部知道此函数的存在,因此无法访问该函数,最终无法模拟它。
也许更重要的是,您不应该在被测对象的内部进行测试,而应该只在 public API 上进行测试。因为那才是最重要的。只要 public API 保持稳定,就没有人关心内部是如何完成的。
我找到了一种使用 babel-plugin-rewire
模块来模拟私有函数的方法。
在 package.json
我有以下内容:
"devDependencies": {
...
"babel-plugin-rewire": "1.0.0-beta-5",
"babel-jest": "18.0.0",
...
在 .babel.rc
我有以下内容:
{
"presets": [
"es2015",
"stage-0",
"react"
],
"env": {
"test": {
"plugins": [
"babel-plugin-rewire"
]
}
},
...
此时我可以模拟私有函数:
import * as moduleToTest from './moduleToTest.js'
describe('#publicFunction', () => {
it('mocks private function', () => {
moduleToTest.__Rewire__('privateFunction', () => {
console.log('I am the mocked private function');
})
...
})
})
如果你想模拟一个私有函数,尝试使用原型。例如,您需要模拟以下 class:
的 privateFunction
export class Module {
public publicFunction() {
// do something
this.privateFunction();
// do something
}
private privateFunction() {
// do something
}
}
所以你应该在jest.spyOn函数中使用Module.prototype。
import { Module } from "./my-module";
describe('MyModule', () => {
it('tests public function', () => {
// Arrange
const module = new Module()
const myPrivateFunc = jest.spyOn(Module.prototype as any, 'privateFunction');
myPrivateFunc.mockImplementation(() => {});
// Act
module.publicFunction();
// Assert
expect(myPrivateFunc).toHaveBeenCalled();
});
});
另一种选择是显式转换:
const spy = jest.spyOn((someInstance as unknown) as { privateMethod: SomeClass['privateMethod'] }, 'privateMethod');
它有点冗长,但它的优点是保留私有方法的类型以供后续检查,如 spy.hasBeenCalledWith(...)
。
我发现使用 ts-jest
.
spyOn
私有方法的最简单方法
首先假设下面的示例 class 使用私有方法 doStuff
你想监视:
class Example{
private doStuff(): void {
...doing stuff
}
}
const example = new Example();
然后就是写间谍的方法
jest.spyOn(example as any, 'doStuff');
我要测试的ES6模块如下所示:
function privateFunction() {
...
}
export function publicFunction() {
... does something ...
privateFunction()
... does something else ...
}
我正在使用 JEST 进行单元测试,我正在尝试找到一种方法来测试 publicFunction
并通过模拟它来避免执行 privateFunction
但我无法在模拟中成功试图。有什么想法吗?
JavaScript的本质是没有办法的。该函数被绑定到模块的范围内,因此无法从外部知道此函数的存在,因此无法访问该函数,最终无法模拟它。
也许更重要的是,您不应该在被测对象的内部进行测试,而应该只在 public API 上进行测试。因为那才是最重要的。只要 public API 保持稳定,就没有人关心内部是如何完成的。
我找到了一种使用 babel-plugin-rewire
模块来模拟私有函数的方法。
在 package.json
我有以下内容:
"devDependencies": {
...
"babel-plugin-rewire": "1.0.0-beta-5",
"babel-jest": "18.0.0",
...
在 .babel.rc
我有以下内容:
{
"presets": [
"es2015",
"stage-0",
"react"
],
"env": {
"test": {
"plugins": [
"babel-plugin-rewire"
]
}
},
...
此时我可以模拟私有函数:
import * as moduleToTest from './moduleToTest.js'
describe('#publicFunction', () => {
it('mocks private function', () => {
moduleToTest.__Rewire__('privateFunction', () => {
console.log('I am the mocked private function');
})
...
})
})
如果你想模拟一个私有函数,尝试使用原型。例如,您需要模拟以下 class:
的 privateFunctionexport class Module {
public publicFunction() {
// do something
this.privateFunction();
// do something
}
private privateFunction() {
// do something
}
}
所以你应该在jest.spyOn函数中使用Module.prototype。
import { Module } from "./my-module";
describe('MyModule', () => {
it('tests public function', () => {
// Arrange
const module = new Module()
const myPrivateFunc = jest.spyOn(Module.prototype as any, 'privateFunction');
myPrivateFunc.mockImplementation(() => {});
// Act
module.publicFunction();
// Assert
expect(myPrivateFunc).toHaveBeenCalled();
});
});
另一种选择是显式转换:
const spy = jest.spyOn((someInstance as unknown) as { privateMethod: SomeClass['privateMethod'] }, 'privateMethod');
它有点冗长,但它的优点是保留私有方法的类型以供后续检查,如 spy.hasBeenCalledWith(...)
。
我发现使用 ts-jest
.
spyOn
私有方法的最简单方法
首先假设下面的示例 class 使用私有方法 doStuff
你想监视:
class Example{
private doStuff(): void {
...doing stuff
}
}
const example = new Example();
然后就是写间谍的方法
jest.spyOn(example as any, 'doStuff');