繁体   English   中英

如何在 NodeJS 中模拟流

[英]How to mock streams in NodeJS

我正在尝试对我的 node-js 模块之一进行单元测试,该模块大量处理流。 我正在尝试模拟一个流(我将写入),因为在我的模块中我有“.on('data/end)”我想触发的侦听器。 基本上我希望能够做这样的事情:

var mockedStream = new require('stream').readable();

mockedStream.on('data', function withData('data') {
  console.dir(data);
});

mockedStream.on('end', function() { 
  console.dir('goodbye');
});

mockedStream.push('hello world');
mockedStream.close();

这会执行,但在我执行推送后“on”事件永远不会被触发(并且 .close() 无效)。

我可以在流上找到的所有指南都使用“fs”或“net”库作为创建新流的基础( https://github.com/substack/stream-handbook ),或者他们用 sinon 模拟它,但是嘲笑变得非常冗长非常快。

有没有一种很好的方法来提供这样的虚拟流?

有一个更简单的方法: stream.PassThrough

我刚刚发现 Node 很容易错过stream.PassThrough类,我相信这就是您正在寻找的。

从节点文档:

stream.PassThrough 类是 Transform 流的一个简单实现,它只是将输入字节传递到输出。 它的目的主要是用于示例和测试...

链接到文档

问题中的代码已修改:

const { PassThrough } = require('stream');
const mockedStream = new PassThrough(); // <----

mockedStream.on('data', (d) => {
    console.dir(d);
});

mockedStream.on('end', function() {
    console.dir('goodbye');
});

mockedStream.emit('data', 'hello world');
mockedStream.end();   //   <-- end. not close.
mockedStream.destroy();

mockedStream.push()可以工作,但作为一个Buffer所以你可能想要这样做: console.dir(d.toString());

而不是使用推送,我应该使用“.emit(<event>, <data>);”

我的模拟代码现在可以工作,看起来像:

var mockedStream = new require('stream').Readable();
mockedStream._read = function(size) { /* do nothing */ };

myModule.functionIWantToTest(mockedStream); // has .on() listeners in it

mockedStream.emit('data', 'Hello data!');
mockedStream.emit('end');

接受答案只是部分正确。 如果您只需要触发事件,则使用.emit('data', datum)是可以的,但是如果您需要将此模拟流通过管道传输到其他任何地方,它就行不通了。

模拟可读流非常简单,只需要可读库。

  let eventCount = 0;
  const mockEventStream = new Readable({
    objectMode: true,
    read: function (size) {
      if (eventCount < 10) {
        eventCount = eventCount + 1;
        return this.push({message: `event${eventCount}`})
      } else {
        return this.push(null);
      }
    }
  });

现在你可以在任何地方传输这个流,'data' 和 'end' 将被触发。

节点文档中的另一个示例: https : //nodejs.org/api/stream.html#stream_an_example_counting_stream

以@flacnut 的回答为基础,我使用Readable.from()执行此操作(在 NodeJS 12+ 中Readable.from()来构造一个预加载数据的流(文件名列表):

    const mockStream = require('stream').Readable.from([
       'file1.txt',
       'file2.txt',
       'file3.txt',
    ])

就我而言,我想模拟 fast-glob.stream 返回的文件名流:

    const glob = require('fast-glob')
    // inject the mock stream into glob module
    glob.stream = jest.fn().mockReturnValue(mockStream)

在被测试的函数中:

  const stream = glob.stream(globFilespec)
  for await (const filename of stream) {
    // filename = file1.txt, then file2.txt, then file3.txt
  }

奇迹般有效!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM