Sinon實作對AWS DynamoDB連線呼叫的模擬
P粉633733146
P粉633733146 2024-03-21 21:36:37
0
2
398

我在 API Gateway 中有一個端點,它會對應到 AWS 中的 Lambda 函數。在為端點的新處理程序函數編寫測試案例時,我不希望 spec 檔案呼叫實際 API 或連接到 DynamoDB。我嘗試添加 sinon.stub,但它仍然呼叫連接到 DynamoDB 並且測試用例失敗。我無法找到存根出錯的地方。

處理程序.js:

saveUser(userName, logger) {
  const Item = {
    id: uuid.v4(),
    userName,
    ttl: parseInt(Date.now() / 1000) + 900 // expire the name after 15 minutes from now
  };
  const params = {
    TableName: "my-table-name",
    Item
  };
  logger.log(`Saving new user name to DynamoDB: ${JSON.stringify(params)}`);

  return new Promise(function(resolve, reject) {
    db.put(params, function(err, _) {
      if (err) {
        logger.exception(`Unable to connect to DynamoDB to create: ${err}`);
        reject({
          statusCode: 404,
          err
        });
      } else {
        logger.log(`Saved data to DynamoDB: ${JSON.stringify(Item)}`);
        resolve({
          statusCode: 201,
          body: Item
        });
      }
    });
  });
}

Handler.spec.js:

import AWS from "aws-sdk";
const db = new AWS.DynamoDB.DocumentClient({
  apiVersion: "2012-08-10"
});

describe("user-name-handler", function() {
  const sandbox = sinon.createSandbox();
  afterEach(() => sandbox.restore());

  it("Test saveUser() method", async function(done) {
    const {
      saveUser
    } = userHandler;

    sandbox.stub(db, "put")
      .returns(new Promise((resolve, _) => resolve({
        statusCode: 200
      })));

    try {
      const result = await saveUser("Sample User", {
        log: () => {},
        exception: () => {}
      });

      expect(result).to.be.equal({
        data: "some data"
      });
      done();
    } catch (err) {
      console.log(err);
      done();
    }
  });
});

錯誤:

Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.

我透過控制台記錄了 err 對象,它給了我這個錯誤,這讓我認為它正在嘗試連接到 DynamoDB。

Error: connect ENETUNREACH 127.0.0.1:80
  at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1144:16) {
message: 'Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1',       
errno: 'ENETUNREACH',
code: 'CredentialsError',
syscall: 'connect',
address: '127.0.0.1',
port: 80,
time: 2023-05-07T10:45:25.835Z,
originalError: {
  message: 'Could not load credentials from any providers',
  errno: 'ENETUNREACH',
  code: 'CredentialsError',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 80,
  time: 2023-05-07T10:45:25.835Z,
  originalError: [Object]
}

相關:如何測試從 AWS DynamoDB 傳回資料的方法

P粉633733146
P粉633733146

全部回覆(2)
P粉714780768

您正在嘲笑測試文件中聲明的 db - 而不是 saveUser 實際使用的 db

解決方案是將 db 宣告移至自己的模組,例如:db.js

const AWS = require("aws-sdk");

const db = new AWS.DynamoDB.DocumentClient({
  apiVersion: "2012-08-10"
});

module.exports = db;

然後從 saveUser 模組和測試中導入它 - 這樣我們就可以模擬 saveUser 使用的同一個 db 實例。

更新

我能夠使用以下程式碼成功執行測試:

測試程式碼:

const sinon = require('sinon');
const { saveUser } = require('../userHandler');
const { expect } = require('chai');

const db = require('../db');

describe('user-name-handler', function() {
  afterEach(() => sinon.restore());

  it('Test saveUser() method', async function() {

      sinon.stub(db, 'put')
        .returns(new Promise((resolve, _) => resolve({
            statusCode: 201,
            body: 'some data'
      })));

      try {
          const result = await saveUser(db, 'Sample User', {
            log: () => {},
            exception: () => {}
          });

          expect(result).to.deep.equal({
            statusCode: 201,
            body: 'some data'
          });
      } catch (err) {
        console.log('err', err);
      }
  });
});

使用者處理程序檔案:

const db = require('./db');

const saveUser = (db, userName, logger) => {
  const Item = {
    id: uuid.v4(),
    userName,
    ttl: parseInt(Date.now() / 1000) + 900 // expire the name after 15 minutes from now
  };
  const params = {
    TableName: "my-table-name"
  };
  logger.log(`Saving new user name to DynamoDB: ${JSON.stringify(params)}`);

    return db.put(params, function(err, _) {
      if (err) {
        logger.exception(`Unable to connect to DynamoDB to create: ${err}`);
        return reject({
          statusCode: 404,
          err
        });
      } else {
        logger.log(`Saved data to DynamoDB: ${JSON.stringify(Item)}`);
        return resolve({
          statusCode: 201,
          body: Item
        });
      }
    });
}

module.exports = { saveUser };

package.json

{
  "name": "play",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "mocha --timeout 5000"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "aws-sdk": "^2.1373.0",
    "chai": "^4.3.7",
    "mocha": "^10.2.0",
    "sinon": "^15.0.4"
  }
}

輸出

#
P粉476046165

在檔案中分離資料庫連線

我們可以將資料庫連線分離到不同的檔案中,並將其匯入到處理程序實作以及 spec 檔案中。

db.js

#
import AWS from "aws-sdk";
const db = new AWS.DynamoDB.DocumentClient({ apiVersion: "2012-08-10" });

export default db;

yields() 函數

存根不應直接傳回 Promise,而應與 .yields() 及其回呼將接受的參數連結。我們可以更改參數以覆蓋程式碼的各個分支。

程式碼

describe("user-handler connection success", function () {
    const sandbox = sinon.createSandbox();
    afterEach(() => sandbox.restore());
    before(() => {
        sinon.stub(db, "put")
            .yields(null, true);
        sinon.stub(db, "get")
            .yields(null, { sampleKey: "sample value" });
        sinon.stub(db, "delete")
            .yields(null, { sampleKey: "sample value" });
    });
    after(() => {
        db.put.restore();
        db.get.restore();
        db.delete.restore();
    });

    it("Test saveUser() method success", async function () {
        const result = await userHandler.saveToken("sample user", {
            log: () => {},
            exception: () => {}
        });

        expect(result.statusCode).to.be.equal(201);
    });
});

有用的連結

https://www.youtube.com/watch?v=vXDbmrh0xDQ

#
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板