67

我有一个名为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调用实际的funcBtestFuncA调用模拟的funcB

我怎样才能在我的两个测试中实现 funcB 被嘲笑和原创?

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

4

7 回答 7

99

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

在这种情况下,funcB 不能以funcA当前编写代码的方式进行模拟。

mock 替换了模块 export for funcB,但funcA不调用模块 export for funcB,它只是funcB直接调用。


内部funcB模拟funcA需要funcA调用模块导出funcB

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


移动funcB到自己的模块

funcB.js

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

助手.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 模块自动支持循环依赖”import ,因此它对模块自身完全有效,因此模块内的函数可以为模块中的其他函数调用模块导出:

助手.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();
  });
});
于 2019-03-16T04:08:03.087 回答
8

迟到的答案,但这应该有效。此外,您应该在自己的文件中测试 funcB,而不是在“助手”测试中。

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

jest.mock('./funcB');

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

        expect(funcBSpy).toHaveBeenCalledTimes(1);
    });
});
于 2020-10-22T11:26:31.270 回答
3
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();
       }
    }
于 2018-08-30T18:08:09.967 回答
2

我创建了一种命名空间来处理这个问题:

let helper = {}

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

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

helper = { funcA, funcB }

module.exports = helper

然后嘲笑很明显jest.fn

于 2020-06-16T09:06:28.203 回答
2

您可以使用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'); 
  });
});

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

于 2021-04-16T06:50:16.267 回答
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>);
   }
}
于 2021-04-12T12:11:57.297 回答
-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();
   }
}
于 2018-07-12T21:00:15.617 回答