<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>streams &amp;mdash; Simple Engineering</title>
    <link>https://getsimple.works/tag:streams</link>
    <description></description>
    <pubDate>Thu, 16 Apr 2026 13:17:20 +0000</pubDate>
    <item>
      <title>How to stub a stream function</title>
      <link>https://getsimple.works/how-to-stub-a-stream-function?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[The stream API provides a heavy-weight asynchronous computation model that keeps a small memory footprint. As exciting as it may sound, testing streams is somehow intimidating. This blog layout some key elements necessary to be successful when mocking stream API.&#xA;&#xA;  We keep in mind that there is a clear difference between mocking versus stub/spying/fakes even though we used mock interchangeably.&#xA;&#xA;In this article we will talk about: &#xA;&#xA;Understanding the difference between Readable and Writable streams &#xA;Stubbing Writable stream&#xA;Stubbing Readable stream &#xA;Stubbing Duplex or Transformer streams &#xA;&#xA;  Even though this blog post was designed to offer complementary materials to those who bought my Testing nodejs Applications book, the content can help any software developer to tuneup working environment. You use this link to buy the book.  Testing nodejs Applications Book Cover&#xA;&#xA;Show me the code&#xA;&#xA;var  gzip = require(&#39;zlib&#39;).createGzip();//quick example to show multiple pipings&#xA;var route = require(&#39;expressjs&#39;).Router(); &#xA;//getter() reads a large file of songs metadata, transform and send back scaled down metadata &#xA;route.get(&#39;/songs&#39; function getter(req, res, next){&#xA;        let rstream = fs.createReadStream(&#39;./several-TB-of-songs.json&#39;); &#xA;        rstream.&#xA;            pipe(new MetadataStreamTransformer()).&#xA;            pipe(gzip).&#xA;            pipe(res);&#xA;        // forwaring the error to next handler     &#xA;        rstream.on(&#39;error&#39;, (error) =  next(error, null));&#xA;});&#xA;&#xA;  At a glance The code is supposed to read a very large JSON file of TB of metadata about songs, apply some transformations, gzip, and send the response to the caller, by piping the results on the response object. &#xA;&#xA;The next example demonstrates how a typical transformer such as MetadataStreamTransformer looks like   &#xA;&#xA;const inherit = require(&#39;util&#39;).inherits;&#xA;const Transform = require(&#39;stream&#39;).Tranform;&#xA;&#xA;function MetadataStreamTransformer(options){&#xA;    if(!(this instanceof MetadataStreamTransformer)){&#xA;        return new MetadataStreamTransformer(options);&#xA;    }&#xA;    this.options = Object.assign({}, options, {objectMode: true});//&lt;= re-enforces object mode chunks&#xA;    Transform.call(this, this.options);&#xA;}&#xA;inherits(MetadataStreamTransformer, Transform);&#xA;MetadataStreamTransformer.prototype.transform = function(chunk, encoding, next){&#xA;    //minimalistic implementation &#xA;    //@todo  process chunk + by adding/removing elements&#xA;    let data = JSON.parse(typeof chunk === &#39;string&#39; ? chunk : chunk.toString(&#39;utf8&#39;));&#xA;    this.push({id: (data || {}).id || random() });&#xA;    if(typeof next === &#39;function&#39;) next();&#xA;};&#xA;&#xA;MetadataStreamTransformer.prototype.flush = function(next) {&#xA;    this.push(null);//tells that operation is over &#xA;    if(typeof next === &#39;function&#39;) {next();}&#xA;};&#xA;&#xA;  Inheritance as explained in this program might be old, but illustrates good enough in a prototypal way that our  MetadataStreamTransformer inherits stuff from Stream#Transformer&#xA;&#xA;What can possibly go wrong?&#xA;&#xA;stubbing functions in stream processing scenario may yield the following challenges:&#xA;&#xA;How to deal with the asynchronous nature of streams &#xA;Identify areas where it makes sense to a stub, for instance: expensive operations &#xA;Identifying key areas needing drop-in replacements, for instance reading from a third party source over the network.&#xA;&#xA;Primer&#xA;&#xA;The keyword when stubbing streams is:&#xA;&#xA;To identify where the heavy lifting is happening. In pure terms of streams, functions that executes read() and write() are our main focus. &#xA;To isolate some entities, to be able to test small parts in isolation. For instance, make sure we test MetadataStreamTransformer in isolation, and mock any response fed into .pipe() operator in other places. &#xA;&#xA;  What is the difference between readable vs writable vs duplex streams? The long answer is available in substack&#39;s Stream Handbook&#xA;&#xA;Generally speaking, Readable streams produce data that can be feed into Writable streams. Readable streams can be .piped on, but not into.  Readable streams have readable|data events, and implementation-wise, implement .read() from Stream#Readable interface. &#xA;&#xA;Writable streams can be .piped into, but not on. For example, res  examples above are piped to an existing stream. The opposite is not always guaranteed. Writable streams also have writable|data events, and implementation-wise, implement .write() from Stream#Writable interface.&#xA;&#xA;Duplex streams go both ways. They have the ability to read from the previous stream and write to the next stream. Transformer streams are duplex, implement .transform() Stream#Transformer interface. &#xA;&#xA;Modus Operandi&#xA;&#xA;How to test the above code by taking on smaller pieces?&#xA;&#xA;fs.createReadStream won&#39;t be tested, but stubbed and returns a mocked readable stream &#xA;.pipe() will be stubbed to return a chain of stream operators&#xA;gzip and res won&#39;t be tested, therefore stubbed to returns a writable+readable mocked stream objects &#xA;rstream.on(&#39;error&#39;, cb) stub readable stream with a read error, spy on next() and check if it has been called upon &#xA;MetadataStreamTransformer will be tested in isolation and MetadataStreamTransformer.transform() will be treated as any other function, except it accepts streams and emits events  &#xA;&#xA;How to stub stream functions &#xA;&#xA;describe(&#39;/songs&#39;, () =  {&#xA;    before(() =  {&#xA;        sinon.stub(fs, &#39;createReadStream&#39;).returns({&#xA;            pipe: sinon.stub().returns({&#xA;                pipe: sinon.stub().returns({&#xA;                    pipe: sinon.stub().returns(responseMock)&#xA;                })&#xA;            }),&#xA;            on: sinon.spy(() =  true)&#xA;        })&#xA;    });&#xA;});&#xA;&#xA;This way of chained stubbing is available in our toolbox. Great power comes with great responsibilities, and wielding this sword may not always be a good idea. &#xA;&#xA;  There is an alternative at the very end of this discussion&#xA;&#xA;The transformer stream class test in isolation may be broken down to&#xA;&#xA;stub the whole Transform instance&#xA;Or stub the .push() and simulate a write by feeding in the readable mocked stream of data&#xA;&#xA;  the stubbed push() is a good place to add assertions&#xA;&#xA;it(&#39;_transform()&#39;, function(){&#xA;    var Readable = require(&#39;stream&#39;).Readable;&#xA;    var rstream = new Readable(); &#xA;    var mockPush = sinon.stub(MetadataStreamTransformer, &#39;push&#39;, function(data){&#xA;        assert.isNumber(data.id);//testing data sent to callers. etc&#xA;        return true;&#xA;    });&#xA;    var tstream = new MetadataStreamTransformer();&#xA;    rstream.push({id: 1});&#xA;    rstream.push({id: 2});&#xA;    rstream.pipe(tstream);&#xA;    expect(tstream.push.called, &#39;#push() has been called&#39;);&#xA;    mockPush.restore(); &#xA;});&#xA;&#xA;How to Mock Stream Response Objects&#xA;&#xA;The classic example of a readable stream is reading from a file. This example shows how mocking fs.createReadStream and returns a readable stream, capable of being asserted on. &#xA;&#xA;//stubb can emit two or more streams + close the stream&#xA;var rstream = fs.createReadStream();&#xA;sinon.stub(fs, &#39;createReadStream&#39;, function(file){ &#xA;    //trick from @link https://stackoverflow.com/a/33154121/132610&#xA;    assert(file, &#39;#createReadStream received a file&#39;);&#xA;    rstream.emit(&#39;data&#39;, &#34;{id:1}&#34;);&#xA;    rstream.emit(&#39;data&#39;, &#34;{id:2}&#34;);&#xA;    rstream.emit(&#39;end&#39;);&#xA;    return false; &#xA;});&#xA;&#xA;var pipeStub = sinon.spy(rstream, &#39;pipe&#39;);&#xA;//Once called this above structure will stream two elements: good enough to simulate reading a file.&#xA;//to stub gzip library: another transformer stream: producing &#xA;var next = sinon.stub();&#xA;//use this function| or call the whole route &#xA;getter(req, res, next);&#xA;//expectations follow: &#xA;expect(rstream.pipe.called, &#39;#pipe() has been called&#39;);&#xA;&#xA;Conclusion&#xA;&#xA;In this article, we established the difference between Readable and Writable streams and how to stub each one of them when unit test. &#xA;&#xA;Testing tends to be more of art, than a science, practice makes perfect. There are additional complimentary materials in the &#34;Testing nodejs applications&#34; book. &#xA;&#xA;References&#xA;&#xA;Testing nodejs Applications book&#xA;More on readable streams(Stream2) ~ Jimmy Chao ~ NeetHack Blog&#xA;QA: Mock Streams ~ StackOverflow Question&#xA;Mock System APIs ~ Gleb Bahmutov Blog&#xA;Streaming to Mongo available for shard-ed clusters ~ mongodb Docs&#xA;Source code of glob stream to know more about using Glob Stream &#xA;How to TDD Streams&#xA;Testing with vinyl for writing to files&#xA;&#xA;tags: #snippets #TDD #streams #nodejs #mocking]]&gt;</description>
      <content:encoded><![CDATA[<p>The stream API provides a heavy-weight asynchronous computation model that keeps a small memory footprint. As exciting as it may sound, testing streams is somehow intimidating. This blog layout some key elements necessary to be successful when mocking stream API.</p>

<blockquote><p>We keep in mind that there is a clear difference between mocking versus stub/spying/fakes even though we used mock interchangeably.</p></blockquote>

<p><strong><em>In this article we will talk about:</em></strong></p>
<ul><li>Understanding the difference between Readable and Writable streams</li>
<li>Stubbing Writable stream</li>
<li>Stubbing Readable stream</li>
<li>Stubbing Duplex or Transformer streams</li></ul>

<blockquote><p>Even though this blog post was designed to offer complementary materials to those who bought my <strong><em><a href="https://bit.ly/2ZFJytb">Testing <code>nodejs</code> Applications book</a></em></strong>, the content can help any software developer to tuneup working environment. <strong><em><a href="https://bit.ly/2ZFJytb">You use this link to buy the book</a></em></strong>.  <a href="https://bit.ly/2ZFJytb"><img src="https://snap.as/a/42OS2vs.png" alt="Testing nodejs Applications Book Cover"/></a></p></blockquote>

<h2 id="show-me-the-code" id="show-me-the-code">Show me the code</h2>

<pre><code class="language-JavaScript">var  gzip = require(&#39;zlib&#39;).createGzip();//quick example to show multiple pipings
var route = require(&#39;expressjs&#39;).Router(); 
//getter() reads a large file of songs metadata, transform and send back scaled down metadata 
route.get(&#39;/songs&#39; function getter(req, res, next){
        let rstream = fs.createReadStream(&#39;./several-TB-of-songs.json&#39;); 
        rstream.
            pipe(new MetadataStreamTransformer()).
            pipe(gzip).
            pipe(res);
        // forwaring the error to next handler     
        rstream.on(&#39;error&#39;, (error) =&gt; next(error, null));
});
</code></pre>

<blockquote><p><strong><em>At a glance</em></strong> The code is supposed to read a very large JSON file of TB of metadata about songs, apply some transformations, <code>gzip</code>, and send the response to the caller, by piping the results on the response object.</p></blockquote>

<p>The next example demonstrates how a typical transformer such as <code>MetadataStreamTransformer</code> looks like</p>

<pre><code class="language-JavaScript">const inherit = require(&#39;util&#39;).inherits;
const Transform = require(&#39;stream&#39;).Tranform;

function MetadataStreamTransformer(options){
    if(!(this instanceof MetadataStreamTransformer)){
        return new MetadataStreamTransformer(options);
    }
    this.options = Object.assign({}, options, {objectMode: true});//&lt;= re-enforces object mode chunks
    Transform.call(this, this.options);
}
inherits(MetadataStreamTransformer, Transform);
MetadataStreamTransformer.prototype._transform = function(chunk, encoding, next){
    //minimalistic implementation 
    //@todo  process chunk + by adding/removing elements
    let data = JSON.parse(typeof chunk === &#39;string&#39; ? chunk : chunk.toString(&#39;utf8&#39;));
    this.push({id: (data || {}).id || random() });
    if(typeof next === &#39;function&#39;) next();
};

MetadataStreamTransformer.prototype._flush = function(next) {
    this.push(null);//tells that operation is over 
    if(typeof next === &#39;function&#39;) {next();}
};
</code></pre>

<blockquote><p>Inheritance as explained in this program might be old, but illustrates good enough in a prototypal way that our  <code>MetadataStreamTransformer</code> inherits stuff from<code>Stream#Transformer</code></p></blockquote>

<h2 id="what-can-possibly-go-wrong" id="what-can-possibly-go-wrong">What can possibly go wrong?</h2>

<p>stubbing functions in stream processing scenario may yield the following challenges:</p>
<ul><li>How to deal with the asynchronous nature of streams</li>
<li>Identify areas where it makes sense to a stub, for instance: expensive operations</li>
<li>Identifying key areas needing drop-in replacements, for instance reading from a third party source over the network.</li></ul>

<h2 id="primer" id="primer">Primer</h2>

<p>The keyword when stubbing streams is:</p>
<ul><li>To identify where the heavy lifting is happening. In pure terms of streams, functions that executes <code>_read()</code> and <code>_write()</code> are our main focus.</li>
<li>To isolate some entities, to be able to test small parts in isolation. For instance, make sure we test <code>MetadataStreamTransformer</code> in isolation, and mock any response fed into <code>.pipe()</code> operator in other places.</li></ul>

<blockquote><p>What is the difference between readable vs writable vs duplex streams? The long answer is available in <a href="https://github.com/substack/stream-handbook"><code>substack</code>&#39;s Stream Handbook</a></p></blockquote>

<p>Generally speaking, Readable streams produce data that can be feed into Writable streams. Readable streams can be <code>.pip</code><strong>ed</strong> on, but not into.  Readable streams have <code>readable|data</code> events, and implementation-wise, implement <code>._read()</code> from <code>Stream#Readable</code> interface.</p>

<p>Writable streams can be <code>.pip</code><strong>ed</strong> into, but not on. For example, <code>res</code>  examples above are piped to an existing stream. The opposite is not always guaranteed. Writable streams also have <code>writable|data</code> events, and implementation-wise, implement <code>_.write()</code> from <code>Stream#Writable</code> interface.</p>

<p>Duplex streams go both ways. They have the ability to read from the previous stream and write to the next stream. Transformer streams are duplex, implement <code>._transform()</code> <code>Stream#Transformer</code> interface.</p>

<h2 id="modus-operandi" id="modus-operandi">Modus Operandi</h2>

<p>How to test the above code by taking on smaller pieces?</p>
<ul><li><code>fs.createReadStream</code> won&#39;t be tested, but stubbed and returns a mocked readable stream</li>
<li><code>.pipe()</code> will be stubbed to return a chain of stream operators</li>
<li><code>gzip</code> and <code>res</code> won&#39;t be tested, therefore stubbed to returns a writable+readable mocked stream objects</li>
<li><code>rstream.on(&#39;error&#39;, cb)</code> stub readable stream with a read error, spy on <code>next()</code> and check if it has been called upon</li>
<li><code>MetadataStreamTransformer</code> will be tested in isolation and <code>MetadataStreamTransformer._transform()</code> will be treated as any other function, except it accepts streams and emits events<br/></li></ul>

<h2 id="how-to-stub-stream-functions" id="how-to-stub-stream-functions">How to stub stream functions</h2>

<pre><code class="language-JavaScript">describe(&#39;/songs&#39;, () =&gt; {
    before(() =&gt; {
        sinon.stub(fs, &#39;createReadStream&#39;).returns({
            pipe: sinon.stub().returns({
                pipe: sinon.stub().returns({
                    pipe: sinon.stub().returns(responseMock)
                })
            }),
            on: sinon.spy(() =&gt; true)
        })
    });
});
</code></pre>

<p>This way of chained stubbing is available in our toolbox. Great power comes with great responsibilities, and wielding this sword may not always be a good idea.</p>

<blockquote><p>There is an alternative at the very end of this discussion</p></blockquote>

<p>The transformer stream class test in isolation may be broken down to</p>
<ul><li>stub the whole Transform instance</li>
<li>Or stub the <code>.push()</code> and simulate a write by feeding in the readable mocked stream of data</li></ul>

<blockquote><p>the stubbed <code>push()</code> is a good place to add assertions</p></blockquote>

<pre><code class="language-JavaScript">it(&#39;_transform()&#39;, function(){
    var Readable = require(&#39;stream&#39;).Readable;
    var rstream = new Readable(); 
    var mockPush = sinon.stub(MetadataStreamTransformer, &#39;push&#39;, function(data){
        assert.isNumber(data.id);//testing data sent to callers. etc
        return true;
    });
    var tstream = new MetadataStreamTransformer();
    rstream.push({id: 1});
    rstream.push({id: 2});
    rstream.pipe(tstream);
    expect(tstream.push.called, &#39;#push() has been called&#39;);
    mockPush.restore(); 
});
</code></pre>

<h2 id="how-to-mock-stream-response-objects" id="how-to-mock-stream-response-objects">How to Mock Stream Response Objects</h2>

<p>The classic example of a readable stream is reading from a file. This example shows how mocking <code>fs.createReadStream</code> and returns a readable stream, capable of being asserted on.</p>

<pre><code class="language-JavaScript">//stubb can emit two or more streams + close the stream
var rstream = fs.createReadStream();
sinon.stub(fs, &#39;createReadStream&#39;, function(file){ 
    //trick from @link https://stackoverflow.com/a/33154121/132610
    assert(file, &#39;#createReadStream received a file&#39;);
    rstream.emit(&#39;data&#39;, &#34;{id:1}&#34;);
    rstream.emit(&#39;data&#39;, &#34;{id:2}&#34;);
    rstream.emit(&#39;end&#39;);
    return false; 
});

var pipeStub = sinon.spy(rstream, &#39;pipe&#39;);
//Once called this above structure will stream two elements: good enough to simulate reading a file.
//to stub `gzip` library: another transformer stream: producing 
var next = sinon.stub();
//use this function| or call the whole route 
getter(req, res, next);
//expectations follow: 
expect(rstream.pipe.called, &#39;#pipe() has been called&#39;);
</code></pre>

<h2 id="conclusion" id="conclusion">Conclusion</h2>

<p>In this article, we established the difference between Readable and Writable streams and how to stub each one of them when unit test.</p>

<p>Testing tends to be more of art, than a science, practice makes perfect. There are additional complimentary materials in the <strong>“Testing <code>nodejs</code> applications”</strong> book.</p>

<h2 id="references" id="references">References</h2>
<ul><li><a href="https://bit.ly/2ZFJytb">Testing <code>nodejs</code> Applications book</a></li>
<li>More on readable streams(Stream2) ~ <a href="https://neethack.com/2013/12/understand-node-stream-what-i-learned-when-fixing-aws-sdk-bug/">Jimmy Chao ~ NeetHack Blog</a></li>
<li>QA: Mock Streams ~ <a href="https://stackoverflow.com/questions/33141012/how-to-mock-streams-in-nodejs">StackOverflow Question</a></li>
<li>Mock System APIs ~ <a href="https://glebbahmutov.com/blog/mock-system-apis/">Gleb Bahmutov Blog</a></li>
<li>Streaming to Mongo available for <code>shard</code>-ed clusters ~ <a href="https://docs.mongodb.com/manual/tutorial/change-streams-example/"><code>mongodb</code> Docs</a></li>
<li>Source code of <a href="https://github.com/wearefractal/glob-stream">glob stream</a> to know more about using Glob Stream</li>
<li><a href="https://stackoverflow.com/q/23141226/132610">How to TDD Streams</a></li>
<li><a href="https://gulpjs.org/writing-a-plugin/testing">Testing with vinyl for writing to files</a></li></ul>

<p>tags: <a href="https://getsimple.works/tag:snippets" class="hashtag"><span>#</span><span class="p-category">snippets</span></a> <a href="https://getsimple.works/tag:TDD" class="hashtag"><span>#</span><span class="p-category">TDD</span></a> <a href="https://getsimple.works/tag:streams" class="hashtag"><span>#</span><span class="p-category">streams</span></a> <a href="https://getsimple.works/tag:nodejs" class="hashtag"><span>#</span><span class="p-category">nodejs</span></a> <a href="https://getsimple.works/tag:mocking" class="hashtag"><span>#</span><span class="p-category">mocking</span></a></p>
]]></content:encoded>
      <guid>https://getsimple.works/how-to-stub-a-stream-function</guid>
      <pubDate>Thu, 17 Jun 2021 06:08:53 +0000</pubDate>
    </item>
    <item>
      <title>Testing nodejs streams</title>
      <link>https://getsimple.works/testing-nodejs-streams?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Asynchronous computation model makes nodejs flexible to perform heavy computations while keeping a relatively lower memory footprint. The stream API is one of those computation models, this article explores how to approach testing it. &#xA;&#xA;In this article we will talk about: &#xA;&#xA;Difference between Readable/Writable and Duplex streams &#xA;Testing Writable stream&#xA;Testing Readable stream &#xA;Testing Duplex or Transformer streams &#xA;&#xA;  Even though this blog post was designed to offer complementary materials to those who bought my Testing nodejs Applications book, the content can help any software developer to tuneup working environment. You use this link to buy the book.  Testing nodejs Applications Book Cover &#xA;&#xA;Show me the code&#xA;&#xA;//Read + Transform +Write Stream processing example&#xA;var gzip = require(&#39;zlib&#39;).createGzip(),&#xA;    route = require(&#39;expressjs&#39;).Router(); &#xA;//getter() reads a large file of songs metadata, transform and send back scaled down metadata &#xA;route.get(&#39;/songs&#39; function getter(req, res, next){&#xA;    let rstream = fs.createReadStream(&#39;./several-tb-of-songs.json&#39;); &#xA;    rstream.&#xA;        .pipe(new MetadataStreamTransformer())&#xA;        .pipe(gzip)&#xA;        .pipe(res);&#xA;    // forwaring the error to next handler     &#xA;    rstream.on(&#39;error&#39;, error =  next(error, null));&#xA;});&#xA;&#xA;//Transformer Stream example&#xA;const inherit = require(&#39;util&#39;).inherits,&#xA;    Transform = require(&#39;stream&#39;).Tranform;&#xA;&#xA;function MetadataStreamTransformer(options){&#xA;    if(!(this instanceof MetadataStreamTransformer)){&#xA;        return new MetadataStreamTransformer(options);&#xA;    }&#xA;    // re-enforces object mode chunks&#xA;    this.options = Object.assign({}, options, {objectMode: true});&#xA;    Transform.call(this, this.options);&#xA;}&#xA;&#xA;inherits(MetadataStreamTransformer, Transform);&#xA;MetadataStreamTransformer.prototype.transform = function(chunk, encoding, next){&#xA;    //minimalistic implementation &#xA;    //@todo  process chunk + by adding/removing elements&#xA;    let data = JSON.parse(typeof chunk === &#39;string&#39; ? chunk : chunk.toString(&#39;utf8&#39;));&#xA;    this.push({id: (data || {}).id || random() });&#xA;    if(typeof next === &#39;function&#39;) next();&#xA;};&#xA;&#xA;MetadataStreamTransformer.prototype.flush = function(next) {&#xA;    this.push(null);//tells that operation is over &#xA;    if(typeof next === &#39;function&#39;) {next();}&#xA;};&#xA;&#xA;  The example above provides a clear picture of the context in which Readable, Writable, and Duplex(Transform) streams can be used.&#xA;&#xA;What can possibly go wrong?&#xA;&#xA;Streams are particularly hard to test because of their asynchronous nature. That is not an exception for I/O on the filesystem or third-party endpoints. It is easy to fall into the integration testing trap when testing nodejs streams. &#xA;&#xA;Among other things, the following are challenges we may expect when (unit) test streams: &#xA;&#xA;Identify areas where it makes sense to stub&#xA;Choosing the right mock object output to feed into stubs&#xA;Mock streams read/transform/write operations&#xA;&#xA;  There is an article dedicated to stubbing stream functions. Mocking in our case will not go into details about the stubbing parts in the current text. &#xA;&#xA;Choosing tools &#xA;&#xA;  If you haven&#39;t already, reading &#34;How to choose the right tools&#34; blog post gives insights on a framework we used to choose the tools we suggest in this blog. &#xA;&#xA;Following our own &#34;Choosing the right tools&#34; framework. They are not a suggestion, rather the ones that made sense to complete this article: &#xA;&#xA;We can choose amongst a myriad of test runners, for instance, jasmine(jasmine-node), ava or jest. mocha was appealing in the context of this writeup, but choosing any other test runner does not make this article obsolete. &#xA;The stack mocha, chai, and sinon (assertion and test doubles libraries) worth a shot.  &#xA;node-mocks-http framework for mocking HTTP Request/Response objects. &#xA;Code under test is instrumented to make test progress possible. Test coverage reporting we adopted, also widely adopted by the mocha community, is istanbul. &#xA;&#xA;Workflow&#xA;&#xA;It is possible to generate reports as tests progress. &#xA;&#xA;  latest versions of istanbul uses the nyc name.&#xA;&#xA;In package.json at &#34;test&#34; - add next line&#xA;  &#34;istanbul test mocha -- --color --reporter mocha-lcov-reporter specs&#34;&#xA;&#xA;Then run the tests using &#xA;$ npm test --coverage &#xA;&#xA;Show me the tests &#xA;&#xA;  If you haven&#39;t already, read the &#34;How to write test cases developers will love&#34;&#xA;&#xA;We assume we approach testing of fairly large nodejs application from a real-world perspective, and with refactoring in mind. The good way to think about large scale is to focus on smaller things and how they integrate(expand) with the rest of the application. &#xA;&#xA;The philosophy about test-driven development is to write failing tests, followed by code that resolves the failing use cases, refactor rinse and repeat. Most real-world, writing tests may start at any given moment depending on multiple variables one of which being the pressure and timeline of the project at hand. &#xA;&#xA;It is not a new concept for some tests being written after the fact (characterization tests). Another case is when dealing with legacy code, or simply ill-tested code base. That is the case we are dealing with in our code sample use case. &#xA;&#xA;The first thing is rather reading the code and identify areas of improvement before we start writing the code. And the clear improvement opportunity is to eject the function getter() out of the router. Our new construct looks as the following: route.get(&#39;/songs&#39;, getter); which allows to test getter() in isolation. &#xA;&#xA;Our skeleton looks a bit as in the following lines. &#xA;&#xA;describe(&#39;getter()&#39;, () =  {&#xA;  let req, res, next, error;&#xA;  beforeEach(() =  {&#xA;    next = sinon.spy();&#xA;    sessionObject = { ... };//mocking session object&#xA;    req = { params: {id: 1234}, user: sessionObject };&#xA;    res = { status: (code) =  { json: sinon.spy() }}&#xA;  });&#xA;    //...&#xA;});&#xA;&#xA;Let&#39;s examine the case where the stream is actually going to fail. &#xA;&#xA;  Note that we lack a way to get the handle on the stream object, as the handler does not return any object to tap into. Luckily, the response and request objects are both instances of streams. So a good mocking can come to our rescue. &#xA;&#xA;//...&#xA;let eventEmitter = require(&#39;events&#39;).EventEmitter,&#xA;  httpMock = require(&#39;node-mocks-http&#39;),&#xA;&#xA;//...&#xA;it(&#39;fails when no songs are found&#39;, done =  {&#xA;    var self = this; &#xA;    this.next = sinon.spy();&#xA;    this.req = httpMock.createRequest({method, url, body})&#xA;    this.res = httpMock.createResponse({eventEmitter: eventEmitter})&#xA;    &#xA;    getter(this.req, this.res, this.next);&#xA;    this.res.on(&#39;error&#39;, function(error){&#xA;        assert(self.next.called, &#39;next() has been called&#39;);&#xA;        done(error);&#xA;    });&#xA;});&#xA;&#xA;Mocking both request and response objects in our context makes more sense. Likewise, we will mock response cases of success, the reader stream&#39;s fs.createReadStream() has to be stubbed and make it eject a stream of fake content. this time, this.res.on(&#39;end&#39;) will be used to make assertions. &#xA;&#xA;Conclusion&#xA;&#xA;Automated testing streams are quite intimidating for newbies and veterans alike. There are multiple enough use cases in the book to get you past that mark.  &#xA;&#xA;In this article, we reviewed how testing tends to be more of art, than science. We also stressed the fact that, like in any art, practice makes perfect ~ testing streams is particularly challenging especially when a read/write is involved. There are additional complimentary materials in the &#34;Testing nodejs applications&#34; book. &#xA;&#xA;References&#xA;&#xA;Testing nodejs Applications book&#xA;&#xA;#snippets #tdd #streams #nodejs #mocking]]&gt;</description>
      <content:encoded><![CDATA[<p>Asynchronous computation model makes <code>nodejs</code> flexible to perform heavy computations while keeping a relatively lower memory footprint. The stream API is one of those computation models, this article explores how to approach testing it.</p>

<p><strong><em>In this article we will talk about:</em></strong></p>
<ul><li>Difference between Readable/Writable and Duplex streams</li>
<li>Testing Writable stream</li>
<li>Testing Readable stream</li>
<li>Testing Duplex or Transformer streams</li></ul>

<blockquote><p>Even though this blog post was designed to offer complementary materials to those who bought my <strong><em><a href="https://bit.ly/2ZFJytb">Testing <code>nodejs</code> Applications book</a></em></strong>, the content can help any software developer to tuneup working environment. <strong><em><a href="https://bit.ly/2ZFJytb">You use this link to buy the book</a></em></strong>.  <a href="https://bit.ly/2ZFJytb"><img src="https://snap.as/a/42OS2vs.png" alt="Testing nodejs Applications Book Cover"/></a></p></blockquote>

<h2 id="show-me-the-code" id="show-me-the-code">Show me the code</h2>

<pre><code class="language-JavaScript">//Read + Transform +Write Stream processing example
var gzip = require(&#39;zlib&#39;).createGzip(),
    route = require(&#39;expressjs&#39;).Router(); 
//getter() reads a large file of songs metadata, transform and send back scaled down metadata 
route.get(&#39;/songs&#39; function getter(req, res, next){
    let rstream = fs.createReadStream(&#39;./several-tb-of-songs.json&#39;); 
    rstream.
        .pipe(new MetadataStreamTransformer())
        .pipe(gzip)
        .pipe(res);
    // forwaring the error to next handler     
    rstream.on(&#39;error&#39;, error =&gt; next(error, null));
});

//Transformer Stream example
const inherit = require(&#39;util&#39;).inherits,
    Transform = require(&#39;stream&#39;).Tranform;

function MetadataStreamTransformer(options){
    if(!(this instanceof MetadataStreamTransformer)){
        return new MetadataStreamTransformer(options);
    }
    // re-enforces object mode chunks
    this.options = Object.assign({}, options, {objectMode: true});
    Transform.call(this, this.options);
}

inherits(MetadataStreamTransformer, Transform);
MetadataStreamTransformer.prototype._transform = function(chunk, encoding, next){
    //minimalistic implementation 
    //@todo  process chunk + by adding/removing elements
    let data = JSON.parse(typeof chunk === &#39;string&#39; ? chunk : chunk.toString(&#39;utf8&#39;));
    this.push({id: (data || {}).id || random() });
    if(typeof next === &#39;function&#39;) next();
};

MetadataStreamTransformer.prototype._flush = function(next) {
    this.push(null);//tells that operation is over 
    if(typeof next === &#39;function&#39;) {next();}
};

</code></pre>

<blockquote><p>The example above provides a clear picture of the context in which Readable, Writable, and Duplex(Transform) streams can be used.</p></blockquote>

<h2 id="what-can-possibly-go-wrong" id="what-can-possibly-go-wrong">What can possibly go wrong?</h2>

<p>Streams are particularly hard to test because of their asynchronous nature. That is not an exception for I/O on the filesystem or third-party endpoints. It is easy to fall into the integration testing trap when testing <code>nodejs</code> streams.</p>

<p>Among other things, the following are challenges we may expect when (unit) test streams:</p>
<ul><li>Identify areas where it makes sense to stub</li>
<li>Choosing the right mock object output to feed into stubs</li>
<li>Mock streams read/transform/write operations</li></ul>

<blockquote><p>There is an article dedicated to <a href="./how-to-stub-a-stream-function">stubbing <code>stream</code> functions</a>. Mocking in our case will not go into details about the stubbing parts in the current text.</p></blockquote>

<h2 id="choosing-tools" id="choosing-tools">Choosing tools</h2>

<blockquote><p>If you haven&#39;t already, reading <a href="./how-to-choose-the-right-tools.md">“How to choose the right tools”</a> blog post gives insights on a framework we used to choose the tools we suggest in this blog.</p></blockquote>

<p>Following our own <em><a href="./how-to-choose-the-right-tools.md">“Choosing the right tools”</a></em> framework. They are not a suggestion, rather the ones that made sense to complete this article:</p>
<ul><li>We can choose amongst a myriad of test runners, for instance, <code>jasmine</code>(<code>jasmine-node</code>), <code>ava</code> or <code>jest</code>. <code>mocha</code> was appealing in the context of this writeup, but choosing any other test runner does not make this article obsolete.</li>
<li>The stack <code>mocha</code>, <code>chai</code>, and <code>sinon</code> (assertion and test doubles libraries) worth a shot.<br/></li>
<li><code>node-mocks-http</code> framework for mocking HTTP Request/Response objects.</li>
<li>Code under test is instrumented to make test progress possible. Test coverage reporting we adopted, also widely adopted by the <code>mocha</code> community, is <code>istanbul</code>.</li></ul>

<h2 id="workflow" id="workflow">Workflow</h2>

<p>It is possible to generate reports as tests progress.</p>

<blockquote><p>latest versions of <code>istanbul</code> uses the <code>nyc</code> name.</p></blockquote>

<pre><code class="language-shell"># In package.json at &#34;test&#34; - add next line
&gt; &#34;istanbul test mocha -- --color --reporter mocha-lcov-reporter specs&#34;

# Then run the tests using 
$ npm test --coverage 
</code></pre>

<h2 id="show-me-the-tests" id="show-me-the-tests">Show me the tests</h2>

<blockquote><p>If you haven&#39;t already, read the <a href="./how-to-write-test-cases-developers-will-love.md">“How to write test cases developers will love”</a></p></blockquote>

<p>We assume we approach testing of fairly large <code>nodejs</code> application from a real-world perspective, and with refactoring in mind. The good way to think about large scale is to focus on smaller things and how they integrate(expand) with the rest of the application.</p>

<p>The philosophy about test-driven development is to write failing tests, followed by code that resolves the failing use cases, refactor rinse and repeat. Most real-world, writing tests may start at any given moment depending on multiple variables one of which being the pressure and timeline of the project at hand.</p>

<p>It is not a new concept for some tests being written after the fact <em>(characterization tests)</em>. Another case is when dealing with legacy code, or simply ill-tested code base. That is the case we are dealing with in our code sample use case.</p>

<p>The first thing is rather reading the code and identify areas of improvement before we start writing the code. And the clear improvement opportunity is to eject the function <code>getter()</code> out of the router. Our new construct looks as the following: <code>route.get(&#39;/songs&#39;, getter);</code> which allows to test <code>getter()</code> in isolation.</p>

<p>Our skeleton looks a bit as in the following lines.</p>

<pre><code class="language-JavaScript">describe(&#39;getter()&#39;, () =&gt; {
  let req, res, next, error;
  beforeEach(() =&gt; {
    next = sinon.spy();
    sessionObject = { ... };//mocking session object
    req = { params: {id: 1234}, user: sessionObject };
    res = { status: (code) =&gt; { json: sinon.spy() }}
  });
    //...
});
</code></pre>

<p>Let&#39;s examine the case where the stream is actually going to fail.</p>

<blockquote><p>Note that we lack a way to get the handle on the stream object, as the handler does not return any object to tap into. Luckily, the response and request objects are both instances of streams. So a good mocking can come to our rescue.</p></blockquote>

<pre><code class="language-JavaScript">
//...
let eventEmitter = require(&#39;events&#39;).EventEmitter,
  httpMock = require(&#39;node-mocks-http&#39;),

//...
it(&#39;fails when no songs are found&#39;, done =&gt; {
    var self = this; 
    this.next = sinon.spy();
    this.req = httpMock.createRequest({method, url, body})
    this.res = httpMock.createResponse({eventEmitter: eventEmitter})
    
    getter(this.req, this.res, this.next);
    this.res.on(&#39;error&#39;, function(error){
        assert(self.next.called, &#39;next() has been called&#39;);
        done(error);
    });
});

</code></pre>

<p>Mocking both request and response objects in our context makes more sense. Likewise, we will mock response cases of success, the reader stream&#39;s <code>fs.createReadStream()</code> has to be stubbed and make it eject a stream of fake content. this time, <code>this.res.on(&#39;end&#39;)</code> will be used to make assertions.</p>

<h2 id="conclusion" id="conclusion">Conclusion</h2>

<p>Automated testing streams are quite intimidating for newbies and veterans alike. There are multiple enough use cases <em><a href="https://bit.ly/2ZFJytb">in the book</a></em> to get you past that mark.</p>

<p>In this article, we reviewed how testing tends to be more of art, than science. We also stressed the fact that, like in any art, practice makes perfect ~ testing streams is particularly challenging especially when a read/write is involved. There are additional complimentary materials in the <strong>“Testing <code>nodejs</code> applications”</strong> book.</p>

<h2 id="references" id="references">References</h2>
<ul><li><a href="https://bit.ly/2ZFJytb">Testing <code>nodejs</code> Applications book</a></li></ul>

<p><a href="https://getsimple.works/tag:snippets" class="hashtag"><span>#</span><span class="p-category">snippets</span></a> <a href="https://getsimple.works/tag:tdd" class="hashtag"><span>#</span><span class="p-category">tdd</span></a> <a href="https://getsimple.works/tag:streams" class="hashtag"><span>#</span><span class="p-category">streams</span></a> <a href="https://getsimple.works/tag:nodejs" class="hashtag"><span>#</span><span class="p-category">nodejs</span></a> <a href="https://getsimple.works/tag:mocking" class="hashtag"><span>#</span><span class="p-category">mocking</span></a></p>
]]></content:encoded>
      <guid>https://getsimple.works/testing-nodejs-streams</guid>
      <pubDate>Wed, 16 Jun 2021 23:46:04 +0000</pubDate>
    </item>
  </channel>
</rss>