我试图对我的一个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()无效)。
我在溪流上找到的所有指导都使用了&#f;'或者' net'库作为创建新流(https://github.com/substack/stream-handbook)的基础,或者他们用sinon模拟它,但是模拟非常冗长非常快。
有没有一种很好的方法来提供像这样的虚拟流?
答案 0 :(得分:12)
我应该使用“.emit(< event>,< data>);”
而不是使用Push。我的模拟代码现在可以工作,看起来像:
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');
答案 1 :(得分:4)
接受答案只是部分正确。如果你只需要触发事件,使用.emit('data', datum)
是可以的,但是如果你需要在任何其他地方管道这个模拟流,它将无法工作。
模拟可读流非常简单,只需要可读的lib。
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);
}
}
});
现在您可以在任何地方管道此流,并且“数据”和“结束”将会触发。
节点docs的另一个例子: https://nodejs.org/api/stream.html#stream_an_example_counting_stream
答案 2 :(得分:3)
有一种更简单的方法: stream.PassThrough
我刚刚发现Node的stream.PassThrough
类很容易错过,我相信这是您想要的。
来自Node文档:
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());
答案 3 :(得分:1)
在@flacnut的答案的基础上,我使用Readable.from()
(在NodeJS 12+中)构造了一个预加载了数据(文件名列表)的流:
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
}
像魅力一样工作!