有没有办法用Jest模拟私有函数?

mat*_*teo 23 javascript unit-testing jestjs es6-modules

我要测试的ES6模块如下所示:

function privateFunction() {
   ...
}
export function publicFunction() {
   ... does something ...
   privateFunction()
   ... does something else ...
}
Run Code Online (Sandbox Code Playgroud)

我正在使用JEST进行单元测试,我正试图找到一种方法来测试publicFunction并通过模拟它来避免执行privateFunction,但我无法在模拟尝试中成功.任何的想法?

mat*_*teo 19

我发现了一种使用babel-plugin-rewire模块来模拟私有函数的方法.

package.json中我有以下内容:

  "devDependencies": {
    ...
    "babel-plugin-rewire": "1.0.0-beta-5",
    "babel-jest": "18.0.0",
    ...
Run Code Online (Sandbox Code Playgroud)

.babel.rc我有以下内容:

{
  "presets": [
    "es2015",
    "stage-0",
    "react"
  ],
  "env": {
    "test": {
      "plugins": [
        "babel-plugin-rewire"
      ]
    }
  },
  ...
Run Code Online (Sandbox Code Playgroud)

此时我能够模拟私有函数:

import * as moduleToTest from './moduleToTest.js'

describe('#publicFunction', () => {
  it('mocks private function', () => {
    moduleToTest.__Rewire__('privateFunction', () => { console.log('I am the mocked private function') })
    ...
  })
})
Run Code Online (Sandbox Code Playgroud)


小智 10

如果要模拟私有函数,请尝试使用原型。例如,您需要模拟以下类的privateFunction

export class Module {
    public publicFunction() {
        // do something
        this.privateFunction();
        // do something
    }

    private privateFunction() {
        // do something
    }
}  
Run Code Online (Sandbox Code Playgroud)

所以你应该在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();
  });
});
Run Code Online (Sandbox Code Playgroud)


And*_*rle 9

没有办法解决JavaScript的本质问题.该函数绑定到模块的范围,因此无法知道此函数是否存在于外部,因此无法访问该函数,最终无法模拟它.

也许更重要的是,您不应该测试被测对象的内部,而只测试公共API.因为这是重要的一切.只要公共API保持稳定,没有人关心内部是如何完成的.

  • 当我使用"tape"和"ava"时,我能够通过使用"babel-plugin-rewire"来模拟私有函数.关于测试私有函数我不同意,因为它违反了TDD的原则. (7认同)
  • 单元测试的本质要求监视和模拟附加到要测试的单元的东西。 (3认同)
  • javascript 的本质是“随时随地做你想做的事”。没有什么可以阻止您插入一个类似名称的函数来断言代码流。 (2认同)

Ren*_*ger 6

另一种选择是显式强制转换:

const spy = jest.spyOn((someInstance as unknown) as { privateMethod: SomeClass['privateMethod'] }, 'privateMethod');
Run Code Online (Sandbox Code Playgroud)

它有点长,但它的优点是保留私有方法的类型以供后续检查,例如spy.hasBeenCalledWith(...).