Is there any way to mock private functions with Jest?

前端 未结 4 1760
遥遥无期
遥遥无期 2020-12-10 01:36

The ES6 module that I want to test looks as follows:

function privateFunction() {
   ...
}
export function publicFunction() {
   ... does something ...
   pr         


        
相关标签:
4条回答
  • 2020-12-10 01:42

    I found out a way to mock my private function by using the babel-plugin-rewire module.

    In package.json I have the following:

      "devDependencies": {
        ...
        "babel-plugin-rewire": "1.0.0-beta-5",
        "babel-jest": "18.0.0",
        ...
    

    In .babel.rc I have the following:

    {
      "presets": [
        "es2015",
        "stage-0",
        "react"
      ],
      "env": {
        "test": {
          "plugins": [
            "babel-plugin-rewire"
          ]
        }
      },
      ...
    

    At this point I was able to mock the private function:

    import * as moduleToTest from './moduleToTest.js'
    
    describe('#publicFunction', () => {
      it('mocks private function', () => {
        moduleToTest.__Rewire__('privateFunction', () => { console.log('I am the mocked private function') })
        ...
      })
    })
    
    0 讨论(0)
  • 2020-12-10 01:53

    If you want to mock private function, try to use prototype. For example, you need to mock privateFunction of the next class:

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

    So you should use Module.prototype in jest.spyOn function.

    import { Module } from "./my-module";
    
    describe('MyModule', () => {
    it('test 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();
      });
    });
    
    0 讨论(0)
  • 2020-12-10 01:53

    There's nothing stopping you from mocking a private function. Don't forget that whatever you insert as a mock becomes a replacement in your module; if you can't access the function you want to test, then add the function yourself.

    Suppose you have some class you wish to test.

    export class MyModule {
      public myPublicFunc() {
        return this.myPrivateFunc();
      }
    
      private myPrivateFunc() {
        return 5;
      }
    }
    

    You can test like this.

    import { MyModule } from './whatever'
    
    describe('MyModule public function', () => {
      it('should call a private function', () => {
        // Arrange
        const mod = new MyModule();
        mod.myPrivateFunc = jest.fn();
    
        // Act
        mod.myPublicFunc();
    
        // Assert
        expect(mod.myPrivateFunc).toHaveBeenCalled();
      });
    });
    

    Typescript will complain if you do exactly as I did, but you can get around that with type casting.

    0 讨论(0)
  • 2020-12-10 01:59

    There is no way through the nature of JavaScript. The function is bound to the scope of the module, so there is no way to know that this function exists from the outside, so no way to access the function and in the end no way to mock it.

    Maybe more important, you should not test on the internals of the object under test but only the public API. Cause that is everything that counts. No one cares how stuff is done internally as long as the public API stays stable.

    0 讨论(0)
提交回复
热议问题