0

我编写了一个测试用例,成功将文件加载到虚拟 FS 中,同时挂载了一个虚拟卷,如下所示

describe("should work", () => {
  const { vol } = require("memfs");
  afterEach(() => vol.reset());
  beforeEach(() => {
    vol.mkdirSync(process.cwd(), { recursive: true });
    jest.resetModules();
    jest.resetAllMocks();
  });

it("should be able to mock fs that being called in actual code", async () => {
    jest.mock("fs", () => {
      return ufs //
        .use(jest.requireActual("fs"))
        .use(createFsFromVolume(vol) as any);
    });
    jest.mock("fs/promises", () => {
      return ufs //
        .use(jest.requireActual("fs/promises"))
        .use(createFsFromVolume(vol) as any);
    });
    const { createFsFromVolume } = require("memfs");
    const { ufs } = require("unionfs");
    const { countFile } = require("../src/ops/fs");

    vol.fromJSON(
      {
        "./some/README.md": "1",
        "./some/index.js": "2",
        "./destination": null,
      },
      "/app"
    );

    const result = ufs.readdirSync(process.cwd());
    const result2 = ufs.readdirSync("/app");
    const result3 = await countFile("/app");

    console.log({ result, result2, result3 });
  });
});

通过使用ufs.readdirSync,我可以访问虚拟 FS,并确实result为我提供了从 加载的文件discvirtual FS表示result2/app是一个从创建的新卷vol.fromJSON

现在我的问题是我无法得到结果result3,这是调用countFile方法如下

import fsPromises from "fs/promises";

export const countFile = async (path: string) => {
  const result = await fsPromises.readdir(path);
  return result.length;
};

我收到错误

错误:ENOENT:没有这样的文件或目录,scandir '/app'

我认为这是因为countFile尽管我已经访问了实际的 FS 而不是虚拟的jest.mock('fs/promises')

请问有人可以提供一些线索吗?

4

1 回答 1

0

这是您要进行单元测试的功能。

//CommonJS version
const fsPromises = require('fs/promises');

const countFile = async (path) => {
  const result = await fsPromises.readdir(path);
  return result.length;
};

module.exports = {
    countFile
}

现在,你通常会怎么做,就是模拟fsPromises. 在此示例中,特别readdir()是因为这是 countFile 中使用的函数。

这就是我们所说的:存根。

软件组件的骨架或特殊用途实现,用于开发或测试调用或以其他方式依赖于它的组件。它替换了一个被调用的组件。

const {countFile} = require('./index');
const {readdir} = require("fs/promises");

jest.mock('fs/promises');

beforeEach(() => {
    readdir.mockReset();
});

it("When testing countFile, given string, then return files", async () => {
    const path = "/path/to/dir";
// vvvvvvv STUB HERE
    readdir.mockResolvedValueOnce(["src", "node_modules", "package-lock.json" ,"package.json"]);
    const res = await countFile(path);
    expect(res).toBe(4);
})

你这样做是因为你在进行单元测试。您不想依赖其他功能,因为这不是单元测试和更多集成测试。其次,它是一个第三方库,由其他人维护/测试。

这是您的方案适用的地方。从我的角度来看,您的目标不是测试countFile(),而是测试fsPromises可能测试读取虚拟文件系统的功能:unionfs. 如果是这样的话,fsPromises就不需要真的被嘲笑了。

于 2022-01-31T17:04:17.823 回答