开玩笑的模拟内部功能

时间:2018-07-10 15:44:00

标签: javascript jestjs

我有一个名为 helper.js 的文件,其中包含两个功能

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

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

我有我的 helper.spec.js 来测试helper.js文件功能。

import {funcA,funcB} from 'helper';

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

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

   }
}

对于funcB的测试非常简单,我将其命名为 someObj
问题是要测试funcA,为了测试它,我想模拟funcB的响应。

我希望 testFuncB 呼叫实际的 funcB testFuncA 嘲笑的 funcB

我如何在两个测试中实现对funcB的模拟和原创?

这不是重复项。这是另一种情况:它们仅模拟内部调用的函数,如果我删除了testFuncB,那将是相同的,但是我也必须对testFuncB进行测试。

7 个答案:

答案 0 :(得分:4)

如果ES6模块直接导出两个函数(不在类,对象等内部,而是直接导出问题中的函数),而一个直接调用另一个,则该调用不能被模拟

在这种情况下,funcBfuncA内不能被模仿。

模拟代替了funcB模块导出,但是funcA并未调用funcB模块导出,它只是直接调用funcB


funcB中模拟funcA要求funcA调用funcB模块导出

这可以通过以下两种方式之一完成:


funcB移至其自己的模块

funcB.js

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

helper.js

import { funcB } from './funcB';

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

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();
  });
});

将模块导入自身

"ES6 modules support cyclic dependencies automatically",因此将模块import嵌入自身是完全有效的,以便该模块中的功能可以为该模块中的其他功能调用 module export

helper.js

import * as helper from './helper';

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

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

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();
  });
});

答案 1 :(得分:2)

最新答案,但是应该可以。 另外,您应该在自己的文件中而不是在“帮助程序”测试中测试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);
    });
});

答案 2 :(得分:1)

我认为这可能有效

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();
   }
}

答案 3 :(得分: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();
       }
    }

答案 4 :(得分:1)

我创建了一种名称空间来处理此问题:

let helper = {}

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

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

helper = { funcA, funcB }

module.exports = helper

然后通过jest.fn

答案 5 :(得分:1)

您可以在测试 funcA 时执行以下技巧:

1.模拟funcB

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

2.将funcB(key)更改为this.funcB(key)

我遇到了同样的问题并且工作了!完整代码:

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

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

测试代码:

import helper from 'helper';

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

答案 6 :(得分:0)

您可以使用 babel-plugin-rewire 提供的 __set__ 函数来模拟内部函数。

假设你已经设置了 babel-plugin-rewire。

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'); 
  });
});

此解决方案的一个优点是您无需更改任何原始代码