【问题标题】:Jest mock nested function by using spyOn, but still call the actual function使用 spyOn 模拟嵌套函数,但仍调用实际函数
【发布时间】:2021-05-23 17:17:01
【问题描述】:

getInfo 在同一个文件中调用getColor。我的意图是模拟 getColor 函数,我将 func.js 作为模块导入并 spyOn getColor。模拟的getColor 应该返回“Red”,但它仍然调用实际函数并返回“Black”。

函数文件

// func.js
function getColor() {
    return "black"
}

function getInfo(){
    const color = getColor()
    const size = "L"
    return `${color}-${size}`
}

module.exports = { getColor, getInfo }

测试文件

// func.test.js
const func = require("./func")

describe("Coverage Change Test", () => {
  beforeAll(() => {
    const colorMock = jest.spyOn(func, "getColor"); // spy on otherFn
    colorMock.mockImplementation(() => "Red");
  });

  afterAll(() => {
    colorMock.resetAllMocks();
  })

  test("return Large Red", async () => {
    const res = func.getInfo();
    expect(res).toEqual("Red-L");
  });
});

我也试过requireActual,但它也调用了实际的。

const { getInfo, getColor } = require('./func');

jest.mock('./func', () => ({
  ...jest.requireActual('./func.'),
  getColor: jest.fn().mockImplementation(() => 'Red'),
}))

describe('test', () => {
  test('returns red', () => {
    const res = getInfo()
    expect(res).toEqual("Red-L")
  })
})

如何在 Jest 中正确模拟嵌套函数?提前致谢。

【问题讨论】:

  • 这是 JS 的天然局限。 getColor 是局部变量,不能在它定义的范围(模块范围)之外修改。要么将这些函数视为 1 个单元并一起测试它们,要么将它们移动到单独的模块中,或者始终将它们用作某个对象上的方法(exports 就像建议的答案一样)。
  • @EstusFlask 感谢您的回复。如果我有const color = await getColor(),如何导出await函数?

标签: node.js unit-testing jestjs mocking spyon


【解决方案1】:

您正在监视 func.getColor 并模拟其实现,但 getInfo 正在调用本地范围的 getColor 函数。您必须更改调用 getColor 的方式才能模拟它。

exports.getColor = function() {
  return 'black'
}

exports.getInfo = function() {
  const color = exports.getColor()
  const size = 'L'
  return `${color}-${size}`
}

【讨论】:

  • 感谢您的回复。我不允许更改功能代码本身。我们可以在测试文件中实现吗?谢谢。
  • @Luke 这很奇怪。您可以使用rewire 覆盖测试中的getColor 函数。
  • 非常感谢。我想我的意图是我不想为了创建单元测试而更改代码。
  • Rewire 在 Jest 中不应该是可行的,他们都破解模块 API 并在它上面竞争。
  • @Luke 你应该是因为你写的不管它如何被测试,这需要修复。
【解决方案2】:

使用 rewire 模块重写您导出的属性。

您的测试文件将如下所示:

const rewire = require('rewire')

describe('test', () => {
  let func;
  let getColorSpy;
  beforeEach(() => {
    getColorSpy = jest.fn()
    func = rewire(__dirname + '/func.js') // import
    func.__set__('getColor', getColorSpy) // rewrite content of getColor
  })
  test('should return Red-L when getColor returns Red', () => {
    getColorSpy.mockReturnValue('Red')

    const res = func.getInfo()

    expect(res).toEqual("Red-L")
  })
})

尽量避免编写像你的模块这样的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 2019-07-14
    • 2017-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多