使用Jest测试文件系统?

时间:2016-12-12 23:54:30

标签: node.js unit-testing jestjs

我使用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在堆栈跟踪中,这让我相信文件系统也在那些测试中被嘲笑(我不想要)。

mock-fs声明:

  

mock-fs @ 4版本将包含重大更改。该库现在覆盖fs,而不是覆盖内置process.binding('fs')模块的所有方法。此更改的目的是避免与覆盖fs方法的其他库(例如graceful-fs)冲突,并且可以使用多个Node版本而无需维护Node&#39的复制和略微修改版本; s fs模块。

我对process.binding的工作原理知之甚少,特别是因为它与Jest并行运行测试有关,但我觉得这是核心问题。

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

3 个答案:

答案 0 :(得分:2)

如果您确实需要针对文件系统进行测试并且模拟文件系统会降低测试的价值,那么您可以针对自己的文件夹运行每个单独的测试,如下所示:

步骤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运行程序实例,此解决方案就可以正常运行。如果需要多次并行测试应用程序,则必须在存储库的副本上运行测试。请记住,在Windows上仍然存在读取文件夹的限制,因此如果您的多个测试需要读取相同的文件夹,那么您很可能需要为每个测试使用不同的源文件夹。

答案 1 :(得分:1)

好的,所以我可以使用依赖注入(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也必须更改,以便我在实际运行时通过实际的fs模块:

import fs from 'fs';

// ...

new ChunksToJsonPlugin(config, fs)

这很有效,现在我的测试并不关心并行/串行运行,但我觉得我可能会在这个过程中讨厌一些NodeJS约定。一般来说,在使用系统导入时我没有看到过多DI,所以我只是为了测试而担心使用这种模式。

仍然知道mock-fs是否可以做到这一点,或者DI是否真的是正确的做法。

答案 2 :(得分:0)

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

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

--runInBand

jest --runInBand