如何用流,承诺和管道一起编写单元测试?

时间:2018-03-14 16:11:13

标签: javascript unit-testing stream mocha

我的功能是

exports.downloadFromBucket = function(fileKey) {
  const localPath = `${process.cwd()}/data/${fileKey}`

  return new Promise((resolve, reject) => {
    const localFile = fs.createWriteStream(localPath)
    const awsStream = s3.getObject({
      Bucket: process.env.UPLOAD_BUCKET,
      Key: fileKey
    })
    .createReadStream()
    .on('error', (err) => {
      logger.info('Error downloading file', err)
      return reject(err)
    })
    .on('finish', () => {
      logger.info('Completed downloading')
      return resolve(localPath)
    })
    .pipe(localFile)
  })
}

我如何使用mochasinon为此编写单元测试?

1 个答案:

答案 0 :(得分:1)

这可能不是最漂亮的解决方案,但假设您要模拟s3fs并测试on('error')on('finish')行为:

您可以使用自定义s3模拟类,使用sinon存储原始s3和fs并触发您要测试的事件。

// Custom S3 Mocking Library
class S3MockLibrary {
  constructor() {
    this.events = {};
  }
  getObject(options) {
    return this;
  }
  createReadStream() {
    return this;
  }
  on(event, func) {
    this.events[event] = func;
    return this;
  }
  pipe(file) {
    return this;
  }
  emit(event, err) {
    this.events[event](err);
  }
}

测试('完成')

it('should verify', async () => {
  const s3Mock = new S3MockLibrary();
  const fsStub = sinon.stub(fs, 'createWriteStream').returns('success');
  const s3Stub = sinon.stub(s3, 'getObject').returns(s3Mock);

  // Emit the finish event async
  setTimeout(() => {
    s3Mock.emit('finish');
  }, 0);
  const result = await downloadFromBucket('test');

  fsStub.restore();
  s3Stub.restore();

  sinon.assert.calledOnce(fsStub);
  sinon.assert.calledOnce(s3Stub);

  assert.equal(result, `${process.cwd()}/data/test`);
});

测试('错误)

it('should fail', async () => {
  const s3Mock = new S3MockLibrary();
  const fsStub = sinon.stub(fs, 'createWriteStream').returns('success');
  const s3Stub = sinon.stub(s3, 'getObject').returns(s3Mock);

  setTimeout(() => {
    s3Mock.emit('error', 'testError');
  }, 0);
  let error;
  await downloadFromBucket('test').catch((err) => {
    error = err;
  });

  fsStub.restore();
  s3Stub.restore();

  sinon.assert.calledOnce(fsStub);
  sinon.assert.calledOnce(s3Stub);

  assert.equal(error, 'testError');
});