【问题标题】:node.js stubbing AWS S3 method in request spec with sinonnode.js 在请求规范中使用 sinon 存根 AWS S3 方法
【发布时间】:2015-07-08 08:15:37
【问题描述】:

我有一个基于express 的应用程序在node.js 0.12.2 上运行,它使用aws-sdk 2.1.22 中的s3.headBucket 方法返回JSON 响应,具体取决于特定存储桶是否存在。

我一直在努力使用 sinon 直接将对 s3.headBucket 的呼叫拒之门外。我已经设法通过创建一个 s3wrapper 模块来解决这个问题,该模块只需要aws-sdk 并实例化并返回s3 变量,但是,我确信这可以在不使用包装器模块的情况下完成,而是可以被存根直接用sinon,有人能指出我正确的方向吗?

下面是当前工作的代码(带有包装模块s3wrapper.js,我想删除并处理我的status_router_spec.js 文件中的存根)。换句话说,我希望能够调用s3.headBucket({Bucket: 'whatever' ... 而不是s3wrapper.headBucket({Bucket: ' ...,并且能够用我自己的响应来结束这个s3.headBucket 调用。

status_router_spec.js

var chai = require('chai'),
    sinon = require('sinon'),
    request = require('request'),
    myHelper = require('../request_helper')

var expect = chai.expect

var s3wrapper = require('../../helpers/s3wrapper')

describe('My router', function () {
  describe('checking the service status', function () {
    var headBucketStub

    beforeEach(function () {
      headBucketStub = sinon.stub(s3wrapper, 'headBucket')
    })

    afterEach(function () {
      s3wrapper.headBucket.restore()
    })

    describe('when no errors are returned', function () {
      it('returns healthy response', function (done) {
        // pass null to represent no errors
        headBucketStub.yields(null)

        request.get(myHelper.appUrl('/status'), function (err, resp, body) {
          if (err) { done(err) }
          expect(JSON.parse(body)).to.deep.eql({
            healthy: true,
            message: 'success'
          })
          done()
        })
      })
    })
  })
})

s3wrapper.js

var AWS = require('aws-sdk')
var s3 = new AWS.S3()

module.exports = s3

status_router.js

var Router = require('express').Router

var s3wrapper = require('../helpers/s3wrapper.js')

var router = new Router()

function statusHandler (req, res) {     
  s3wrapper.headBucket({Bucket: 'some-bucket-id'}, function (err) {
    if (err) {
      return res.json({ healthy: false, message: err })
    } else {
      return res.json({ healthy: true, message: 'success' })
    }
  })
}

router.get(/^\/status\/?$/, statusHandler)

module.exports = router

【问题讨论】:

  • s3wrapper.headBucket 的存根对我来说看起来不错(尽管您可以删除引用并直接调用 s3wrapper.headBucketStub.yields(null)),但是 request.get 呢?这也需要被存根,并且回调产生了。
  • 我在测试中明确使用headBucketStub.yields(null) 的原因是因为我实际上有几个不同的测试,我希望headBucket 方法为每个测试返回不同的值。至于request.get,我实际上也想要这个,因为这是一个请求测试,所以我正在向一个为测试设置的服务器实例发送一个实际请求。经过进一步调查,如果我从status_router 模块中导出s3 变量,我就可以摆脱s3wrapper,尽管这并不是真正的改进
  • 我遇到了同样的问题,但即使我使用包装器也不起作用。
  • @kunde 尝试发布您的代码,也许有人可以提供一些帮助。我相信我难以取消调用的原因是因为在请求规范中,您需要启动一个服务器,如果您要直接调用它,看起来我正在对 S3 库进行存根,但是一旦它通过服务器,请求到达未存根版本。创建 S3 包装器允许我将 S3 调用存根,并且我还切换到使用 supertest 模块来运行我的服务器。
  • @adamc 原来我使用错误的包装器。我只在测试中需要包装器,但在我需要测试的模块中不需要。在分析了情况之后,您可以存根包装的 s3 实例是有道理的,因为没有包装器,您正在尝试存根不同的实例。如果没有包装器,我不知道该怎么做,但这样对我来说很好。

标签: node.js amazon-s3 sinon aws-sdk


【解决方案1】:

为了@ippomakunochi 的利益而回答这个问题,他要求后续回复。

我们最终使用rewire 直接在 s3 库上设置存根。例如,我们使用以下代码对 s3 库的 getObject 调用进行了存根:

s3stub = { getObject: sinon.stub(), listObjects: sinon.stub() }
revert = s3.__set__('s3', s3stub)

这是完整的代码:

../../../build/app/helpers/s3

var AWS = require('aws-sdk');
var s3 = new AWS.S3();

module.exports = {
  get: function get(options, callback) {
    var requestOptions = { Bucket: module.exports.bucket(), Key: options.productId + '.json' };

    s3.getObject(requestOptions, function (err, data) {
      if (err) { // handle err }

        try {
          var productData = JSON.parse(data.Body);
        } catch (e) {
          // handle error
        }
        return callback(null, productData);
      });
    }
  }
}

test/unit/app/helpers/s3_spec.js

var AWS = require('aws-sdk')
var chai = require('chai')
var sinon = require('sinon')
var sinonChai = require('sinon-chai')
var chaiSubset = require('chai-subset')
var rewire = require('rewire')

var s3 = rewire('../../../build/app/helpers/s3')

chai.use(chaiSubset)
chai.use(sinonChai)

var expect = chai.expect

describe('S3', function () {
  var s3stub, revert

  beforeEach(function () {
    s3stub = { getObject: sinon.stub(), listObjects: sinon.stub() }
    revert = s3.__set__('s3', s3stub)
  })

  afterEach(function () {
    revert()
  })

  describe('#get', function () {
    context('when no errors are returned by s3', function () {
      it('returns a product', function (done) {
        var productResponse = helper.fixture.body('product.json')
        s3stub.getObject.yields(null, productResponse)

        s3.get({ productId: '1234' }, function (err, res) {
          expect(err).to.not.exist

          expect(res).to.containSubset({name: 'long sleeve shirt', 'retailer_code': 'retailer-1'})
          done()
        })
      })
    })

    context('when s3 returns a NoSuchKey error', function () {
      it('returns a NotFoundError', function (done) {
        var s3Error = AWS.util.error(new Error(), { name: 'NoSuchKey' })
        s3stub.getObject.yields(s3Error)

        s3.get({ productId: '1234' }, function (err) {
          expect(err.message).to.eql('1234 is not found in s3')
          expect(err.output.statusCode).to.eql(404)
          done()
        })
      })
    })
  })

【讨论】:

    猜你喜欢
    • 2011-06-23
    • 1970-01-01
    • 2021-09-26
    • 2019-01-28
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 2016-02-19
    • 2015-04-18
    相关资源
    最近更新 更多