如何使用 Jest 测试 express + dynamodb?

How to test express + dynamodb using Jest?

我是 Jest 和单元测试的新手,我在 AWS.Express 的无服务器(Lambda)上部署了一个 express API api 使用 dynamodb 进行 crud 操作

注意:- 我的 api 是基于 express 的,而不仅仅是普通节点,因为在 jest website 上他们告诉了普通 nodejs

我能够对不使用的方法进行单元测试 dynamodb.However 对于使用 dynamodb 的方法,它失败了,据我所知,这与 dynamodb 是远程的有关,因为 app.js 中的代码对应于使用 lambda 在 aws 上托管的 dyanmo 数据库。

我该怎么做?

注意:- 我的 api 是基于 express 而不是简单的节点

const isUrl = require('is-url');
const AWS = require('aws-sdk');
const { nanoid } = require('nanoid/async');
const express = require('express');

const router = express.Router();
const dynamoDb = new AWS.DynamoDB.DocumentClient();

// URL from users

router.post('/', async (req, res, next) => {
  // urlId contains converted short url characters generated by nanoid

  const urlId = await nanoid(8);
  const { longUrl } = req.body;

  // Veryfying url Format using isUrl, this return a boolean
  const checkUrl = isUrl(longUrl);
  if (checkUrl === false) {
    res.status(400).json({ error: 'Invalid URL, please try again!!!' });
  }

  const originalUrl = longUrl;
  const userType = 'anonymous'; // user type for anonymous users
  const tableName = 'xxxxxxxxxxxxx'; // table name for storing url's

  const anonymousUrlCheckParams = {
    TableName: tableName,
    Key: {
      userId: userType,
      originalUrl,
    },
  };

  dynamoDb.get(anonymousUrlCheckParams, (err, data) => {
    const paramsForTransaction = {
      TransactItems: [
        {
          Put: {
            TableName: tableName,
            Item: {
              userId: userType,
              originalUrl,
              convertedUrl: `https://xxxxxxxxxxxxxxxx/${urlId}`,
            },
          },
        },

        {
          Put: {
            TableName: tableName,
            Item: {
              userId: urlId,
              originalUrl,
            },
            ConditionExpression: 'attribute_not_exists(userId)',
          },
        },
      ],
    };
    if (err) {
      console.log(err);
      res
        .status(500)
        .json({ error: 'Unknown Server Error, Please Trimify Again!' });
    } else if (Object.keys(data).length === 0 && data.constructor === Object) {
      dynamoDb.transactWrite(paramsForTransaction, async (error) => {
        if (error) {
          // err means converted value as userId is repeated twice.

          console.log(error);
          res
            .status(500)
            .json({ error: 'Unknown Server Error, Please trimify again. ' });
        } else {
          res.status(201).json({
            convertedUrl: `https://xxxxxxxxxxxx/${urlId}`,
          });
        }
      });
    } else {
      res.status(201).json({
        convertedUrl: data.Item.convertedUrl,
      });
    }
  });
});

module.exports = router;

我的test.js

const request = require('supertest');
const app = require('../app');

test('Should convert url from anonymous user ', async () => {
  await request(app)
    .post('/anon-ops/convert')
    .send({
      longUrl: 'https://google.com',
    })
    .expect(201);
});

首先,如果您想进行单元测试。您是否使用 express js 并不重要,因此,jest 网站上的示例和信息非常有效,可以帮助您上路。

进行单元测试的难易程度主要取决于您构建代码的方式。例如,您可以将所有 express js 特定代码保存在单独的文件中,然后仅在单元测试期间实例化包含实际业务逻辑(有些人可能称为服务层)的文件。这至少是您可以让自己更轻松的一种方式。使用函数式方法还可以让您的代码更易于测试,或者至少可以使用依赖注入,因此您可以在测试期间交换依赖项,以便单独测试某些功能。

谈到 DynamoDB,您有两个选择。模拟或 运行 本地版本。

您可以使用 jest mocks or using a mocking library such as sinon 模拟您正在调用的特定函数。选择哪个主要是个人喜好。

第二个选项是运行一个local version of DynamoDB in a docker container。这也有验证您对 DynamoDB 服务的实际调用的好处(您可以通过验证模拟来完成,但在验证中很容易出错),但是,设置起来更麻烦,您的测试将是速度较慢,因此这可能会使您的测试偏向于更多的集成测试而不是单元测试(但这种区别本身就是一个晚上的价值或争论)。

如果您想对整个 API 进行端到端测试,可以查看 SuperTest NPM package

(编辑)添加了使用 sinon

的小示例
const AWS = require('aws-sdk');
const sinon = require('sinon');

const ddb = new AWS.DynamoDB.DocumentClient();

const getStub = sinon.stub(AWS.DynamoDB.DocumentClient.prototype, "get");

getStub.callsFake((params, cb) => {
  cb(null, {result: []});
});

ddb.get({foo: 'bar'}, (err, val) => {
  console.log(val); // => { "result": [] }
})