有什么办法可以用 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');