在NodeJS中使用流进行TDD /测试

Mic*_*ser 35 testing tdd stream node.js

我一直试图找到一种合理的方法来测试使用流的代码.有没有人找到合理的方法/框架来帮助测试在nodejs中使用流的代码?

例如:

var fs = require('fs'),
    request = require('request');

module.exports = function (url, path, callback) {
  request(url)
    .pipe(fs.createWriteStream(path))
    .on('finish', function () {
      callback();
    });
};
Run Code Online (Sandbox Code Playgroud)

我目前测试这种类型代码的方法或者包括使用流来简化代码,以至于我可以将它抽象为未经测试的代码块,或者通过编写类似这样的代码:

var rewire = require('rewire'),
    download = rewire('../lib/download'),
    stream = require('stream'),
    util = require('util');

describe('download', function () {
  it('should download a url', function (done) {
    var fakeRequest, fakeFs, FakeStream;

    FakeStream = function () {
      stream.Writable.call(this);
    };

    util.inherits(FakeStream, stream.Writable);

    FakeStream.prototype._write = function (data, encoding, cb) {
      expect(data.toString()).toEqual("hello world")
      cb();
    };

    fakeRequest = function (url) {
      var output = new stream.Readable();

      output.push("hello world");
      output.push(null);

      expect(url).toEqual('http://hello');

      return output;
    };

    fakeFs = {
      createWriteStream: function (path) {
        expect(path).toEqual('hello.txt');
        return new FakeStream();
      }
    };

    download.__set__('fs', fakeFs);
    download.__set__('request', fakeRequest);

    download('http://hello', 'hello.txt', function () {
      done();
    });

  });
});
Run Code Online (Sandbox Code Playgroud)

有没有人想出更优雅的测试流方式?

nfr*_*ure 13

为此目的做了最好的测试.它不仅使流测试更清洁,而且还允许测试V1和V2流https://www.npmjs.com/package/streamtest


Mar*_*eck 7

我也一直在使用memorystream,但后来将我的断言放入finish事件中.这样看起来更像是对正在测试的流的真实使用:

require('chai').should();

var fs = require('fs');
var path = require('path');

var MemoryStream = require('memorystream');
var memStream = MemoryStream.createWriteStream();

/**
 * This is the Transform that we want to test:
 */

var Parser = require('../lib/parser');
var parser = new Parser();

describe('Parser', function(){
  it('something', function(done){
    fs.createReadStream(path.join(__dirname, 'something.txt'))
      .pipe(parser)
      .pipe(memStream)
      .on('finish', function() {

        /**
         * Check that our parser has created the right output:
         */

        memStream
          .toString()
          .should.eql('something');
        done();
      });
  });
});
Run Code Online (Sandbox Code Playgroud)

检查对象可以这样做:

var memStream = MemoryStream.createWriteStream(null, {objectMode: true});
.
.
.
      .on('finish', function() {
        memStream
          .queue[0]
          .should.eql({ some: 'thing' });
        done();
      });
.
.
.
Run Code Online (Sandbox Code Playgroud)


Wes*_*y92 5

将 Stream 读入内存并将其与预期的 Buffer 进行比较。

it('should output a valid Stream', (done) => {
  const stream = getStreamToTest();
  const expectedBuffer = Buffer.from(...);
  let bytes = new Buffer('');

  stream.on('data', (chunk) => {
    bytes = Buffer.concat([bytes, chunk]);
  });

  stream.on('end', () => {
    try {
      expect(bytes).to.deep.equal(expectedBuffer);
      done();
    } catch (err) {
      done(err);
    }
  });
});
Run Code Online (Sandbox Code Playgroud)


mar*_*-gj 3

我感觉你很痛苦。

我不知道有什么框架可以帮助进行流测试,但是如果看一下这里,我正在开发一个流库,您可以看到我如何解决这个问题。

这是我正在做的事情的一个想法。

var chai = require("chai")
, sinon = require("sinon")
, chai.use(require("sinon-chai"))
, expect = chai.expect
, through2 = require('through2')
;

chai.config.showDiff = false

function spy (stream) {
  var agent, fn
  ;
  if (spy.free.length === 0) {
    agent = sinon.spy();
  } else {
    agent = spy.free.pop();
    agent.reset();
  }
  spy.used.push(agent);
  fn = stream._transform;
  stream.spy = agent;
  stream._transform =  function(c) {
    agent(c);
    return fn.apply(this, arguments);
  };
  stream._transform = transform;
  return agent;
};

spy.free = [];
spy.used = [];


describe('basic through2 stream', function(){

  beforeEach(function(){
    this.streamA = through2()
    this.StreamB = through2.obj()
    // other kind of streams...

    spy(this.streamA)
    spy(this.StreamB)

  })

  afterEach(function(){
    spy.used.map(function(agent){
      spy.free.push(spy.used.pop())
    })
  })

  it("must call transform with the data", function(){
    var ctx = this
    , dataA = new Buffer('some data')
    , dataB = 'some data'
    ;

    this.streamA.pipe(through2(function(chunk, enc, next){
      expect(ctx.streamA.spy).to.have.been.calledOnce.and.calledWidth(dataA)
    }))

    this.streamB.pipe(through2(function(chunk, enc, next){
      expect(ctx.streamB.spy).to.have.been.calledOnce.and.calledWidth(dataB)
    }))

    this.streamA.write(dataA)
    this.streamB.write(dataB)

  })

})
Run Code Online (Sandbox Code Playgroud)

请注意,我的间谍函数包装了该_transform方法并调用我的间谍并调用原始方法 _transform

此外,该afterEach功能正在回收间谍,因为您最终可能会创建数百个间谍。

当您想要测试异步代码时,问题就变得困难了。然后向你最好的朋友许诺。我上面给出的链接有一些示例。