我在 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粉7147807682024-03-22 18:19:12
您正在嘲笑測試文件中聲明的 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粉4760461652024-03-22 16:16:37
我們可以將資料庫連線分離到不同的檔案中,並將其匯入到處理程序實作以及 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
#