Skip to content

Mocking the File System

模拟文件系统可以确保测试不依赖于实际的文件系统,从而使测试更加可靠和可预测。这种隔离有助于避免之前测试产生的副作用。它允许测试错误条件和边缘情况,而这些情况在实际文件系统中可能难以或无法复制,例如权限问题、磁盘满场景或读写错误。

Vitest 没有开箱即用地提供任何文件系统模拟 API。你可以使用 vi.mock 手动模拟 fs 模块,但这很难维护。相反,我们推荐使用 memfs 来为你完成这项工作。memfs 创建一个内存中的文件系统,它模拟文件系统操作而不触及实际磁盘。这种方法快速且安全,避免了对真实文件系统的任何潜在副作用。

Example

为了自动将每个 fs 调用重定向到 memfs,你可以在项目的根目录下创建 __mocks__/fs.cjs__mocks__/fs/promises.cjs 文件:

ts
// we can also use `import`, but then
// every export should be explicitly defined

const { fs } = require('memfs')
module.exports = fs
ts
// we can also use `import`, but then
// every export should be explicitly defined

const { fs } = require('memfs')
module.exports = fs.promises
read-hello-world.js
ts
import { readFileSync } from 'node:fs'

export function readHelloWorld(path) {
  return readFileSync(path, 'utf-8')
}
hello-world.test.js
ts
import { beforeEach, expect, it, vi } from 'vitest'
import { fs, vol } from 'memfs'
import { readHelloWorld } from './read-hello-world.js'

// tell vitest to use fs mock from __mocks__ folder
// this can be done in a setup file if fs should always be mocked
vi.mock('node:fs')
vi.mock('node:fs/promises')

beforeEach(() => {
  // reset the state of in-memory fs
  vol.reset()
})

it('should return correct text', () => {
  const path = '/hello-world.txt'
  fs.writeFileSync(path, 'hello world')

  const text = readHelloWorld(path)
  expect(text).toBe('hello world')
})

it('can return a value multiple times', () => {
  // you can use vol.fromJSON to define several files
  vol.fromJSON(
    {
      './dir1/hw.txt': 'hello dir1',
      './dir2/hw.txt': 'hello dir2',
    },
    // default cwd
    '/tmp',
  )

  expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1')
  expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2')
})

Released under the MIT License.