使用 Jest 进行 JavaScript 模拟 - 模拟依赖函数

问题描述 投票:0回答:1

我有两个用 JavaScript 编写的模块。在一个模块中,我有一个生成随机数的函数,在另一个模块中,有一个基于该随机数从数组中选择元素的函数。示例如下:

随机数.js

export function generateRandomNumber() {
  return a random number
}

selectElement.js

import { generateRandomNumber } from './randomNumber.js'

export function selectRandomElement() {
  const myArray = ['a', 'b', 'c', 'd']
  const randomNumber = generateRandomNumber()

  return myArray[randomNumber]
}

以上是sudo代码。我简化了实际代码。

我想使用 Jest 来测试 selectElement.js 模块。该模块依赖于其他模块中的generateRandomNumber 函数。我想模拟该函数,以便每次调用 selectRandomElement 时,我都会得到完全相同的结果(再次,sudo 代码):

__tests__/selectElement.test.js

import { selectRandomElement } from '../selectElement.js'

const generateRandomNumber = () => 0  // use this as the mock

test('check we get the letter a', () => {
  expect(selectRandomElement()).toBe('a') //  returns 'a' (the first element from the array)
  expect(selectRandomElement()).toBe('a') //  returns 'a' (the first element from the array)
  expect(selectRandomElement()).toBe('a') //  returns 'a' (the first element from the array)
  expect(selectRandomElement()).toBe('a') //  returns 'a' (the first element from the array)
});

我的目的是在测试中产生一致的行为。即它总是返回“a”,因为当我在测试中调用 selectRandomElement 时,我将始终获得数组的第一个元素,因为它使用模拟函数。

可以这样做吗?

我想使用ESM,并保留模块的结构不变。没有重构。只能更改测试文件。

javascript unit-testing jestjs mocking
1个回答
0
投票

我已经解决了这个问题。我原来的模拟代码有点不对劲。为了使这项工作有效,需要改变很多事情:

  1. jest.mock(...
    需要更改为
    jest.unstable_mockModule(...
    。模拟不在我的原始代码中,但如果您遇到此问题,它可能在您的代码中。如果不知道该怎么办,请参阅下文。
  2. 您必须使用动态导入。即
    const { generateRandomNumber } = await import('../randomNumber.js')
    。您必须在
    await
    之前包含
    import ()
  3. 动态导入必须低于模拟减速度。
  4. 您已经在模拟中定义了
    __esModule: true
  5. 您的 jest 配置文件中必须有
    "transform": {}
    请参阅此处的列表项目 1 了解详细信息。如果您使用 Typescript,则需要更改此设置。这不是专门针对模拟的。我添加它是为了完整性。

您无需更改任何源代码来适应这一点。

这是我上面的测试脚本,其中包含所需的所有更新。

__tests__/selectElement.test.js

import { selectRandomElement } from '../selectElement.js'

jest.unstable_mockModule('../randomNumber.js', () => ({
  __esModule: true,  // Point 4 in the list above
  generateRandomNumber: jest.fn(() => 0)
}))

//  Point 3 in the list above. jest.unstable_mockModule is defined first.
//  The dynamic import is defined second.
const { generateRandomNumber } = await import('../randomNumber.js')  //  Point 2 in the list above

test('check we get the letter a', () => {
  expect(selectRandomElement()).toBe('a')  //  returns 'a' (the first element from the array)
  expect(selectRandomElement()).toBe('a')  //  returns 'a' (the first element from the array)
  expect(selectRandomElement()).toBe('a')  //  returns 'a' (the first element from the array)
  expect(selectRandomElement()).toBe('a')  //  returns 'a' (the first element from the array)
});
© www.soinside.com 2019 - 2024. All rights reserved.