[英]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.