用开玩笑测试文件系统



我正在使用mock-fs尝试测试我编写的WebPack插件,该插件修改了文件系统上的文件。

这是测试:

test('writes chunks to build/assets.json if no json file present', () => {
   mockFs({
    [buildDir]: {},
  });
  const stats = new Stats({
    assetsByChunkName: {
      main: 'main.somecrazyhash12341213445345.js',
    },
  });
  const compiler = new Compiler(stats);
  const plugin = new ChunksToJsonPlugin(config);
  expect(fs.existsSync(assetFilePath)).toBe(false);
  plugin.apply(compiler);
  compiler.execHandler();
  expect(fs.existsSync(assetFilePath)).toBe(true);
  expect(fs.readFileSync(assetFilePath, 'utf-8')).toEqual(
    JSON.stringify({
      main: 'main.somecrazyhash12341213445345.js',
    })
  );
  mockFs.restore();
});

当我单独运行它时,它可以很好地工作,但是当我作为套件的一部分运行时,其他测试(不使用mock-fs)中断。

SS http://d.pr/i/z2ne

我注意到mock-fs在StackTrace中,这使我相信文件系统也在这些测试中被模拟(我不想要)。

mock-fs指出:

Mock-FS@4版本将包含破坏更改。该库现在覆盖process.binding('fs'),而不是覆盖内置fs模块的所有方法。此更改的目的是避免与覆盖fs方法(例如graceful-fs)的其他库发生冲突,并使得可以与多个节点版本一起使用而不维护Node的fs模块的复制版本和稍微修改的版本。

我对process.binding的工作原理还不够了解,尤其是与Jest -and and and and and and of jest conters and and and of jest and跑步测试有关,但我觉得这是核心问题。

我该如何完成这项工作?是否有另一种方法可以在不使用mock-fs的情况下测试此行为?

如果您确实需要针对文件系统进行测试并嘲笑文件系统将降低测试的值,那么您可以针对自己的文件夹运行每个单独的测试,如下:

步骤1:声明基本文件夹

const DIR_BASE = path.resolve(__dirname, '__fixtures__/mytestedmodule');

步骤2:为每个测试创建一个唯一的子文件夹名称

it('should ...', async () => {
  const DIR_ID = md5('should ...');
  const DIR = path.resolve(DIR_BASE, `data${DIR_ID}`);
  await mytestedmodule(DIR);
  expect(...);
});
  • 这里的MD5用于创建测试名称的唯一哈希,以便测试可以彼此独立运行。
  • 请注意data${DIR_ID}:下一步将使用数据作为后测试的模式

步骤3:清洁所有尚未清洁的文件夹

afterAll(async () => {
  const folders =
    (await fs.readdir(DIR_BASE))
      .filter((folder) => folder.match('data'));
  const promises = [];
  for (const folder of folders) {
    promises.push(fs.remove(path.resolve(DIR_BASE, folder)));
  }
  return Promise.all(promises);
});

只要您只有一个在文件夹上运行的单个Jest Runner实例,此解决方案就可以使用。如果您需要并行多次测试应用程序,则必须在存储库的副本上运行测试。请记住,在Windows上读取文件夹仍有一个限制,因此,如果您的多个测试需要读取相同的文件夹,则您很可能需要对每个测试具有不同的源文件夹。

<</p>

好吧,所以我可以使用依赖项注入(di),抛弃mock-fs以支持memfs

import memfs from 'memfs';
// ...
test('writes chunks to build/assets.json if no json file present', () => {
  // eslint-disable-next-line new-parens
  const fs = new memfs.Volume;
  fs.mountSync(buildDir, {});
  // same as before
  const plugin = new ChunksToJsonPlugin(config, fs);
  // ------------------------------------------ ^^
  expect(fs.existsSync(assetFilePath)).toBe(false);
  // same as before
  expect(fs.existsSync(assetFilePath)).toBe(true);
  expect(fs.readFileSync(assetFilePath, 'utf-8')).toEqual(
    JSON.stringify({
      main: 'main.somecrazyhash12341213445345.js',
    })
  );
});

相应地,我对ChunksToJsonPlugin的API也必须更改,因此在运行LIVE时我会通过实际的fs模块传递:

import fs from 'fs';
// ...
new ChunksToJsonPlugin(config, fs)

这有效,现在我的测试不在乎并行/串行运行,但是我觉得我可能会在此过程中降低一些nodejs约定。通常,我在使用系统导入时没有看到太多DI,所以我担心仅出于测试而使用这种模式。

仍然可以知道mock-fs是否可以知道这是否可以,或者DI实际上是此处正确的方法。

我今天遇到了类似的问题,事实证明,由于它们并行运行,我的设置和拆除方法会影响其他测试套件。

为了防止这种情况,请尝试在运行测试套件时添加以下标志。

--runInBand

即。

jest --runInBand

最新更新