Pertanyaan TDD / pengujian dengan streaming di NodeJS


Saya sudah mencoba menemukan cara yang masuk akal untuk menguji kode yang menggunakan aliran. Adakah yang menemukan cara / kerangka yang masuk akal untuk membantu menguji kode yang menggunakan streaming dalam nodejs?

Sebagai contoh:

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

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

Cara saya saat ini menguji jenis kode ini baik melibatkan menyederhanakan kode dengan aliran begitu banyak sehingga saya bisa abstrak itu ke bagian kode yang tidak diuji atau dengan menulis sesuatu seperti ini:

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();
    });

  });
});

Adakah yang datang dengan cara pengujian aliran yang lebih elegan?


32
2018-04-17 18:55


asal


Jawaban:


Dibuat streamtest untuk tujuan itu. Ini tidak hanya membuat tes aliran bersih tetapi juga memungkinkan untuk menguji aliran V1 dan V2 https://www.npmjs.com/package/streamtest


10
2017-08-04 09:07



Saya juga telah menggunakan aliran memori, tetapi kemudian menempatkan pernyataan saya ke dalam finish peristiwa. Dengan cara itu terlihat lebih seperti penggunaan nyata dari streaming yang sedang diuji:

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();
      });
  });
});

Memeriksa objek dapat dilakukan seperti ini:

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

6
2018-06-25 09:30



Aku merasakanmu sakit.

Saya tidak tahu kerangka apa pun untuk membantu menguji dengan streaming, tetapi jika dilihat sini, tempat saya mengembangkan pustaka streaming, Anda dapat melihat bagaimana saya mendekati masalah ini.

di sini adalah gagasan tentang apa yang saya lakukan.

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)

  })

})

Perhatikan bahwa fungsi mata-mata saya membungkus _transform metode dan memanggil mata-mata saya dan memanggil yang asli _transform 

Juga afterEach fungsinya mendaur ulang mata-mata, karena Anda dapat menciptakan ratusan dari mereka.

Masalahnya menjadi sulit adalah ketika Anda ingin menguji kode async. Kemudian janjikan sahabatmu. Tautan yang saya berikan di atas memiliki beberapa contoh itu.


3
2018-05-17 22:30



Baca Stream ke dalam memori dan bandingkan dengan Buffer yang diharapkan.

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);
    }
  });
});

3
2018-05-09 00:44



Saya belum pernah menggunakan ini, dan itu sudah cukup tua, tapi https://github.com/dominictarr/stream-spec mungkin membantu.


2
2017-09-03 10:48



Anda dapat menguji aliran menggunakan MemoryStream dan sinon dengan menggunakan mata-mata. Berikut ini cara saya menguji beberapa kode saya.

describe('some spec', function() {
    it('some test', function(done) {
        var outputStream = new MemoryStream();

        var spyCB = sinon.spy();

        outputStream.on('data', spyCB);

        doSomething(param, param2, outputStream, function() {
            sinon.assert.calledWith(spyCB, 'blah');

            done();
        });
    });
});

2
2018-05-18 13:51



Cara terbaik yang saya temukan adalah menggunakan acara

const byline = require('byline');
const fs = require('fs');

it('should process all lines in file', function(done){
   //arrange
   let lines = 0;
   //file with 1000 lines
   let reader = fs.readFileStream('./input.txt');
   let writer = fs.writeFileStream('./output.txt');
   //act
   reader.pipe(byline).pipe(writer);
   byline.on('line', function() {
     lines++;
   });
   //assert
   writer.on('close', function() {
     expect(lines).to.equal(1000);
     done();
   });
});

dengan melewati dilakukan sebagai panggilan balik, mocha menunggu sampai dipanggil sebelum melanjutkan.


1
2017-10-10 18:44