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

如何测试写入流时的错误?Node.js流测试异常排查

问题:测试可写流_write方法抛出的异常无法被捕获

我正在测试应用中不同模块抛出的错误。该应用会把多文件上传请求的流通过加密管道传输到S3存储桶。

我能在加密流的_read方法里模拟异常并被正确捕获,但在目标可写流的_write方法里用同样方式抛出异常时,会出现未处理异常的情况。

下面是能正常运行的测试代码(模拟加密流抛出错误):

it('error in encryption stream',  async () => {

    const encryptionStream = new DuplexMock();
    encryptionStream._read = () => { 
        throw new Error('Test Exception') 
    };
    const writeStream = new BufferWritableMock();

    CryptoService.encryptionStream.mockImplementation(()=> encryptionStream);
    S3Service.uploadFromStream.mockImplementation(() => writeStream);

    const result = await supertest(appInstance)
        .post(`${storePath}?skip-encryption=false`)
        .attach('file', filePath);

    expect(result.statusCode).toBe(500);

});

是不是我的处理方式有问题?

更新1

之前为排查问题把encryptionStream改成了DuplexMock,但实际应该用PassThrough;另外原代码里writeStream没被调用,现在已经更新了上面的代码。

更新2

下面是无法正常运行的测试代码(模拟S3可写流抛出错误):

it('error in S3 stream', async () => {
    const encryptionStream = new PassThrough();
    const writeStream = new ObjectWritableMock();
    writeStream._write = (chunk, enc, next) => {
        new Error('Test Exception');
    };

    CryptoService.encryptionStream.mockImplementation(()=> encryptionStream);
    S3Service.uploadFromStream.mockImplementation(() => writeStream);
             
    const result = await supertest(appInstance)
        .post(`${storePath}?skip-encryption=false`)
        .attach('file', filePath)
        
    expect(result.statusCode).toBe(500);
        
    }, 10*1000
);

解决方案

问题出在可写流_write方法的异常处理逻辑上,Node.js流的_write有特定的错误处理规则:

  1. 错误传递方式错误
    在_write里直接throw Error或者只创建Error实例不处理都无效,因为_write是异步方法,抛出的异常会进入Node.js全局异常处理,不会被流的错误事件捕获。正确做法是通过回调函数next传递错误:

    writeStream._write = (chunk, enc, next) => {
        // 调用next并传入错误对象,触发流的error事件
        next(new Error('Test Exception'));
    };
    
  2. 确保业务代码监听流的error事件
    你的应用代码必须给S3可写流添加error事件监听,否则即使通过next传递错误,也会变成未处理异常。比如业务代码里应该有类似逻辑:

    const s3Stream = S3Service.uploadFromStream();
    s3Stream.on('error', (err) => {
        // 终止请求并返回500状态码
        res.status(500).send('上传失败');
    });
    
  3. 修正测试代码的错误逻辑
    你当前的测试代码里,new Error('Test Exception')只是创建了错误对象但未传递,完全不会触发错误流程。必须通过next回调把错误传递出去,这样流才会触发error事件,被应用的错误处理逻辑捕获,最终返回500状态码。

调整后的测试代码如下:

it('error in S3 stream', async () => {
    const encryptionStream = new PassThrough();
    const writeStream = new ObjectWritableMock();
    writeStream._write = (chunk, enc, next) => {
        // 通过next传递错误
        next(new Error('Test Exception'));
    };

    CryptoService.encryptionStream.mockImplementation(()=> encryptionStream);
    S3Service.uploadFromStream.mockImplementation(() => writeStream);
             
    const result = await supertest(appInstance)
        .post(`${storePath}?skip-encryption=false`)
        .attach('file', filePath)
        
    expect(result.statusCode).toBe(500);
        
}, 10*1000);

内容的提问来源于stack exchange,提问作者Dog Ears

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:03:23