我有两个用 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,并保留模块的结构不变。没有重构。只能更改测试文件。
我已经解决了这个问题。我原来的模拟代码有点不对劲。为了使这项工作有效,需要改变很多事情:
jest.mock(...
需要更改为jest.unstable_mockModule(...
。模拟不在我的原始代码中,但如果您遇到此问题,它可能在您的代码中。如果不知道该怎么办,请参阅下文。const { generateRandomNumber } = await import('../randomNumber.js')
。您必须在 await
之前包含 import ()
。__esModule: true
。"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)
});