You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jest中为异步生成器函数编写单元测试并正确Mock ReadStream

解决方案

问题根因

你当前测试失败的核心原因是 mock 的 fs.createReadStream 返回了空对象,没有实现 Symbol.asyncIterator 异步迭代器接口,无法被 for await...of 语法遍历。

具体实现方案

有两种常用的实现方式,都可以正确模拟可迭代的 ReadStream 对象:

方案1:手动实现异步迭代器(轻量无额外依赖)

直接给 mock 返回的对象挂载异步迭代器方法,返回你预设的测试块即可,不需要引入额外依赖。

方案2:用 Node 内置 Readable 生成模拟流

如果需要更贴近真实流的行为,可以用 stream.Readable.from 直接生成可迭代的流对象,适配更复杂的流行为测试场景。

完整修改后的测试代码

import fs from 'fs';
import os from 'os';
import path from 'path';
import { WorkDirUtils } from './你的模块路径';

// jest.mock 要放在模块作用域顶部,不要放在 describe 内部
jest.mock('fs');
jest.mock('os');

describe('Work Dir Utils', () => {
  let workDirUtils: WorkDirUtils;
  // 预设的测试块数据
  const mockChunks = [Buffer.from('first chunk'), Buffer.from('second chunk'), Buffer.from('last chunk')];

  beforeEach(() => {
    (os.tmpdir as jest.Mock).mockReturnValue('/tmp');
    (fs.mkdtempSync as jest.Mock).mockReturnValue('/tmp/folder/pref-rand');
    //  mock createReadStream返回带异步迭代器的对象,用方案1的实现
    (fs.createReadStream as jest.Mock).mockReturnValue({
      [Symbol.asyncIterator]: async function* () {
        for (const chunk of mockChunks) yield chunk;
      }
    });
    // 方案2的实现替换上面的mock返回值即可:
    // (fs.createReadStream as jest.Mock).mockReturnValue(require('stream').Readable.from(mockChunks));
    workDirUtils = new WorkDirUtils();
    workDirUtils.createTempDir('pref-');
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  it('should read chunks of a file using generator', async () => {
    const testFile = path.join(__dirname, './fixtures/manifest.ts');
    const testChunkSize = 1024 * 1024 * 1024;
    const receivedChunks: Buffer[] = [];

    for await (const chunk of workDirUtils.readChunks(testFile, testChunkSize)) {
      expect(chunk).toBeInstanceOf(Buffer);
      receivedChunks.push(chunk);
    }

    // 校验返回的块和预设的一致
    expect(receivedChunks).toEqual(mockChunks);
    // 校验createReadStream参数传递正确
    expect(fs.createReadStream).toHaveBeenCalledWith(
      path.join('/tmp/folder/pref-rand', testFile),
      { highWaterMark: testChunkSize }
    );
  });
});

额外优化建议

  • 可以单独新增测试用例覆盖异常分支,验证 cwd 未设置时是否正确抛出错误
  • 如果需要测试流报错场景,可以在模拟的异步迭代器中主动抛出错误,验证上层逻辑的容错处理

内容的提问来源于stack exchange,提问作者Balint Laszlo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 17:45:00