javascript - 如何将流、 promise 和管道一起编写单元测试?

标签 javascript unit-testing stream mocha.js

我的职能是

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 为此编写单元测试?

最佳答案

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

您可以使用自定义 s3 模拟类,用 sinon stub 原始 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');
});

关于javascript - 如何将流、 promise 和管道一起编写单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49282667/

相关文章:

javascript - 使用其编辑器并排 Markdown 预览滚动

java - 如何使用 JUnit 在 Java 中测试具有 boolean 返回类型的方法

c# 如何发送仍在写入的文件流并一直发送到创建结束

Ruby 压缩流

c# - 将大字符串写入文件的最佳方法

javascript - 选择组件Vue JS - 默认选择值

javascript - 将 HTML/Javascript 解析到 MySQL 数据库中

javascript - 元素是与 If 语句结合的语句,在悬停时没有正确响应

android - 如何使用 Kotlin 运行单个 Android 测试?

c++ - 使用输入迭代器时的单元测试