Sinon implementiert die Simulation von AWS DynamoDB-Verbindungsaufrufen
P粉633733146
P粉633733146 2024-03-21 21:36:37
0
2
384

Ich habe einen Endpunkt im API Gateway, der einer Lambda-Funktion in AWS zugeordnet ist. Wenn ich Testfälle für die neue Handlerfunktion des Endpunkts schreibe, möchte ich nicht, dass die spec-Datei die eigentliche API aufruft oder eine Verbindung zu DynamoDB herstellt. Ich habe versucht, sinon.stub hinzuzufügen, aber es ruft immer noch „Connect to DynamoDB“ auf und der Testfall schlägt fehl. Ich kann nicht finden, wo der Stub schief geht.

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

Fehler:

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

Ich habe das err-Objekt über die Konsole protokolliert und es hat mir diesen Fehler angezeigt, der mich vermuten lässt, dass es versucht, eine Verbindung zu DynamoDB herzustellen.

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]
}

Verwandt: So testen Sie Methoden, die Daten von AWS DynamoDB zurückgeben

P粉633733146
P粉633733146

Antworte allen(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

Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage