简体   繁体   English

Jest 模拟内部 function

[英]Jest mock inner function

I have one file called helper.js that consist of two functions我有一个名为helper.js的文件,其中包含两个函数

export const funcA = (key) => {
   return funcB(key)
};

export const funcB = (key,prop) => {
   return someObj;
};

I have my helper.spec.js to test the helper.js file functions.我有我的helper.spec.js来测试 helper.js 文件功能。

import {funcA,funcB} from 'helper';

describe('helper', () => {
   test('testFuncB', () => {

   }
   test('testFuncA', () => {

   }
}

The test for funcB is pretty simple i just call it and expect someObj funcB 的测试非常简单,我只是调用它并期望someObj
The problem is to test funcA, in order to test it i want to mock the response of funcB.问题是测试 funcA,为了测试它我想模拟 funcB 的响应。

I want testFuncB call the actual funcB and testFuncA call mocked funcB我希望testFuncB调用实际的funcB ,而testFuncA调用模拟的funcB

How can i achieve funcB to be mocked and original in my two tests?我怎样才能在我的两个测试中实现 funcB 被嘲笑和原创?

This is not a duplicate.这不是重复的。 It is a different case: they mock inner called functions only, if I remove the testFuncB then it will be the same but I must perform test on testFuncB too.这是一个不同的情况:他们只模拟内部调用的函数,如果我删除 testFuncB 那么它将是相同的但我也必须对 testFuncB 执行测试。

If an ES6 module directly exports two functions (not within a class, object, etc., just directly exports the functions like in the question) and one directly calls the other, then that call cannot be mocked .如果一个 ES6 模块直接导出两个函数(不在类、对象等中,只是直接导出问题中的函数)并且一个直接调用另一个,那么该调用不能被模拟

In this case, funcB cannot be mocked within funcA the way the code is currently written.在这种情况下, funcB不能funcA当前编写代码的方式。

A mock replaces the module export for funcB , but funcA doesn't call the module export for funcB , it just calls funcB directly.有模拟将替换模块出口funcB ,但funcA不调用该模块出口funcB ,它只是调用funcB直接。


Mocking funcB within funcA requires that funcA call the module export for funcB .惩戒funcBfuncA要求funcA呼吁模块出口funcB

That can be done in one of two ways:这可以通过以下两种方式之一完成:


Move funcB to its own modulefuncB移动到它自己的模块

funcB.js函数B.js

export const funcB = () => {
  return 'original';
};

helper.js helper.js

import { funcB } from './funcB';

export const funcA = () => {
  return funcB();
};

helper.spec.js helper.spec.js

import * as funcBModule from './funcB';
import { funcA } from './helper';

describe('helper', () => {

  test('test funcB', () => {
    expect(funcBModule.funcB()).toBe('original');  // Success!
  });

  test('test funcA', () => {
    const spy = jest.spyOn(funcBModule, 'funcB');
    spy.mockReturnValue('mocked');

    expect(funcA()).toBe('mocked');  // Success!

    spy.mockRestore();
  });
});

Import the module into itself将模块导入自身

"ES6 modules support cyclic dependencies automatically" so it is perfectly valid to import a module into itself so that functions within the module can call the module export for other functions in the module: “ES6 模块自动支持循环依赖”,因此import模块导入自身是完全有效的,以便模块内的函数可以调用模块中其他函数的模块导出

helper.js helper.js

import * as helper from './helper';

export const funcA = () => {
  return helper.funcB();
};

export const funcB = () => {
  return 'original';
};

helper.spec.js helper.spec.js

import * as helper from './helper';

describe('helper', () => {

  test('test funcB', () => {
    expect(helper.funcB()).toBe('original');  // Success!
  });

  test('test funcA', () => {
    const spy = jest.spyOn(helper, 'funcB');
    spy.mockReturnValue('mocked');

    expect(helper.funcA()).toBe('mocked');  // Success!

    spy.mockRestore();
  });
});

Late answer but this should work.迟到的答案,但这应该有效。 Also you should test funcB in its own file and not inside the 'helper' tests.此外,您应该在其自己的文件中而不是在“帮助程序”测试中测试 funcB。

import { funcB } from './funcB';
import { funcA } from './helper';

jest.mock('./funcB');

describe('helper', () => {
    test('test funcA', () => {
        const funcBSpy = jest.fn();
        funcB.mockImplementation(() => funcBSpy());

        expect(funcBSpy).toHaveBeenCalledTimes(1);
    });
});
import * as helper from 'helper';

    describe('helper', () => {
       it('should test testFuncA', () => {
          const mockTestFuncB = jest.mock();
          // spy on calls to testFuncB and respond with a mock function

           mockTestFuncB.spyOn(helper, 'testFuncB').mockReturnValue(/*your expected return value*/);

          // test logic

          // Restore helper.testFuncB to it's original function
          helper.testFuncB.mockRestore();
       }
    }

I create a kind of nameSpace to handle this issue:我创建了一种名称空间来处理这个问题:

let helper = {}

const funcA = (key) => {
   return helper.funcB(key)
};

const funcB = (key,prop) => {
    return someObj;
};

helper = { funcA, funcB }

module.exports = helper

and then mocking is obvious with jest.fn然后用jest.fn进行嘲讽很明显

You can do the following trick when you test the funcA :测试funcA时,您可以执行以下技巧:

1.Mock the funcB : 1.模拟funcB

helper.funcB = jest.fn().mockImplementationOnce(() => <your data>);

2.Change the funcB(key) to this.funcB(key) 2.把funcB(key) this.funcB(key)

I had the same problem and worked!我遇到了同样的问题并且工作了! Full Code:完整代码:

export const funcA = (key) => {
    return this.funcB(key)
};

export const funcB = (key,prop) => {
    return someObj;
};

Test Code:测试代码:

import helper from 'helper';

describe('helper', () => {
   test('testFuncB', () => {
       ...
   }
   test('testFuncA', () => {
       helper.funcB = jest.fn().mockImplementationOnce(() => <your data>);
   }
}

You can use babel-plugin-rewire provided __set__ function to mock internal function.你可以使用babel-plugin- __set__提供的__set__函数来模拟内部函数。

Assuming you have set up babel-plugin-rewire.假设你已经设置了 babel-plugin-rewire。

helper.spec.js helper.spec.js

import {funcA, __set__} as helper from './helper';

describe('helper', () => {
  test('test funcA', () => {
    __set__('funcB', () => {
      return 'funcB return value'
    })

    expect(funcA()).toBe('funcB return value'); 
  });
});

One advantage of this solution is you don't need to change any original code此解决方案的一个优点是您无需更改任何原始代码

I was able to get this working.我能够让这个工作。 I separated my helper and my main logic into two files like other solutions.像其他解决方案一样,我将助手和主要逻辑分成两个文件。 In the test file, I had to mock the entire helper file.在测试文件中,我不得不模拟整个帮助文件。

const { doAdd } = require('./addHelper');

function add(a, b) {
  return doAdd(a, b);
}
jest.mock('./addHelper');

// ...

it('should call doAdd', () => {
  // hook into doAdd helper method and intercept its return value
  jest.spyOn(helperModule, 'doAdd').mockReturnValue(11);

  expect(addModule.add()).toEqual(11);
  expect(helperModule.doAdd).toBeCalled();
});

Here is my solution:这是我的解决方案:

https://github.com/davidholyko/jest-sandbox https://github.com/davidholyko/jest-sandbox

I think this might work我认为这可能有效

import * as helper from 'helper';

describe('helper', () => {
   test('testFuncB', () => {

   }
   test('testFuncA', () => {
      const mockTestFuncB = jest.mock();
      // spy on calls to testFuncB and respond with a mock function
      jest.spyOn(helper, 'testFuncB').mockImplementationOnce(mockTestFuncB);

      // Do the testing ...

      // Restore helper.testFuncB to it's original function
      helper.testFuncB.mockRestore();
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM