【问题标题】:Testing the file system with Jest?用 Jest 测试文件系统?
【发布时间】:2017-04-27 22:54:30
【问题描述】:

我正在使用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 的fs 模块的复制和稍微修改的版本。

我不太了解 process.binding 的工作原理,尤其是它与 Jest 并行运行测试有关,但我觉得这是核心问题。

我怎样才能做到这一点?有没有其他方法可以在不使用mock-fs 的情况下测试这种行为?

【问题讨论】:

    标签: node.js unit-testing jestjs


    【解决方案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】:

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

      第 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 上,读取文件夹仍然存在限制,因此如果您的多个测试需要读取同一个文件夹,您很可能需要为每个测试使用不同的源文件夹。

      【讨论】:

        【解决方案3】:

        我今天遇到了类似的问题,结果证明我的设置和拆除方法正在影响其他测试套件,因为它们是并行运行的。

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

        --runInBand
        

        jest --runInBand
        

        【讨论】:

          猜你喜欢
          • 2020-02-13
          • 1970-01-01
          • 2014-03-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-21
          相关资源
          最近更新 更多