Rstest 支持对模块进行 mock,这使得你可以在测试中替换模块的实现。Rstest 提供了 rs
(别名 rstest
)工具函数来进行模块的 mock 。你可以直接使用以下方法来 mock 模块:
<T = unknown>(moduleName: string | Promise<T>, moduleFactory?: (() => Promise<Partial<T>> | Partial<T>)) => void
调用 rs.mock
时,Rstest 会对第一个参数对应的模块进行 mock 替换。rs.mock
将根据是否提供了第二个 mock 工厂函数来决定如何处理被 mock 的模块,下面会详细介绍这两种情况。
需要注意的是:rs.mock
会被提升到当前模块的顶部,所以即使在调用 rs.mock('some_module')
前执行了 import fn from 'some_module'
,some_module
也会在一开始被 mock。
根据提供的第二个参数,rs.mock
有两种行为:
rs.mock
方法的第二个参数提供了一个工厂函数,则替换为工厂函数的返回值(工厂函数可以是异步函数,取异步函数 await 后的返回值)作为被 mock 的模块的实现。如果 rs.mock
方法调用时没有提供工厂函数,则会尝试去解析与被 mock 的模块在同级的 __mocks__
目录下的同名模块,具体的 mock 的解析的规则如下:
__mocks__
文件夹与正在 mock 的文件同级,其中 __mocks__
文件夹包含一个与被 mock 的模块同名的文件,则 Rstest 将使用该文件作为 mock 的实现。__mocks__
文件夹,其中包含一个与被 mock 的模块同名的文件,则 Rstest 将使用该文件作为 mock 实现。fs
、path
等),并且在根目录中有一个 __mocks__
文件夹,其中包含一个与内置模块同名的文件(如 __mocks__/fs.mjs
、__mocks__/path.ts
等),则 Rstest 将使用该文件作为对应的 mock 实现(使用 node:
协议导入内置模块时将忽略 node:
前缀)。例如项目中有这样的文件结构:
那么在如下的测试文件中尝试 mock lodash
和 src/multiple
模块,他们会被替换为 __mocks__/lodash.js
和 src/__mocks__/multiple.ts
中的实现。
rs.mock
和 rs.doMock
也支持第一个参数传入一个 Promise<T>
,并将这个 T
的类型作为第二个工厂函数 await 后的返回值(Promise<T>
),这能够让 IDE 获得更好的类型提示,并对工厂函数的返回值做类型校验。传入 Promise<T>
除对类型提示有增强外,对 mock 模块能力没有任何影响。
<T = unknown>(moduleName: string | Promise<T>, moduleFactory?: (() => Promise<Partial<T>> | Partial<T>)) => void
与 rs.mock
类似,rs.doMock
也会 mock 模块,但它不会被提升到模块顶部。它会在被执行到时调用,这意味着,如果在调用 rs.doMock
之前已经导入了模块,则该模块不会被 mock,而在调用 rs.doMock
之后导入的模块会被 mock。
<T = Record<string, unknown>>(path: string) => Promise<T>
无视一个模块是否被 mock,导入其原始的模块。如果你想 mock 模块的部分实现,可以使用 rs.importActual
来获取原始模块的实现与 mock 的实现进行合并进行部分 mock。
<T = Record<string, unknown>>(path: string) => Promise<T>
导入一个模块及其所有属性的 mock 实现。
(path: string) => void
取消指定模块的 mock 实现。之后所有对 import
的调用都将返回原始模块,即使它之前已被 mock。与 rs.mock
类似,此调用被提升到文件的顶部,因此它将仅取消在 setupFiles
中执行的模块 mock。
(path: string) => void
与 rs.unmock
相同,但不会被提升到文件顶部。模块的下一次导入将导入原始模块而不是 mock。这不会取消 mock 之前导入的模块。
resetModules: () => RstestUtilities
清除所有模块的缓存。这允许在重新导入时重新执行模块。这在隔离不同测试中共享的模块的状态时非常有用。
不会重置被 mock 的 modules。要清除 mock 的模块,请使用 rs.unmock
或 rs.doUnmock
。