【问题标题】:Mocking database when testing microservice functions测试微服务功能时模拟数据库
【发布时间】:2017-10-27 04:58:53
【问题描述】:

我用 pg-promise 创建了一个基本的 NodeJS 微服务。我已经通过 express 创建了包含 API 的路由文件 (index.js):

var express = require('express');
var router = express.Router();

var db = require('./../queries');

router.get('/api/puppy', db.getAllPuppies);
router.post('/api/puppy', db.createPuppy);

module.exports = router;

然后我在 queries.js 文件中添加了这两个函数:

var promise = require('bluebird');

var options = {
  promiseLib: promise
};

var config = require('./config.json');
var pgp = require('pg-promise')(options);
var connectionString = process.env.DB_PATH || "postgres://postgres:xxxx@localhost:5432/postgres";
var db = pgp(connectionString);


function getAllPuppies(req, res, next) {
  db.any('select * from puppy')
    .then(function (data) {
      res.status(200)
        .json({
          status: 'success',
          data: data,
        });
    })
    .catch(function (err) {
      return next(err);
    });
}


function createPuppy(req, res, next) {
  db.none('insert into ' +
    'puppy(name, description) ' +
    'values(${name}, ${description})',
    req.body)
    .then(function () {
      res.status(200)
        .json({
          status: 'success',
        });
    })
    .catch(function (err) {
      return next(err);
    });
}


module.exports = {
  getAllPuppies,
  createPuppy,
};

该应用程序运行良好。我现在想以一种或另一种方式测试这两个函数,但我有点卡在应该模拟数据库的方式(我正在使用 Mocha 和诸如 beforeEach 之类的函数)来检索或创建数据。

【问题讨论】:

  • 感谢 Vitaly,在示例中,查询是经过测试的,但不是实际功能。
  • 哦,写得很好的教程中有很多:blog.jscrambler.com/testing-apis-mocha-2
  • 嗨 Vitaly,非常感谢。我已经尝试过本教程,但这使用了 lowdb 和 json 文件。我尝试使用这些示例并根据我的目的对其进行修改,但无济于事,我非常沮丧。
  • 数据库与API测试完全无关。您只是在测试请求 + 响应,而不是处理程序中的内容。

标签: javascript node.js database postgresql pg-promise


【解决方案1】:

一般来说,您有两种选择:

  1. 使用依赖注入并发送模拟数据库服务
  2. 将您的测试环境配置为使用测试数据库,以便您可以按原样使用数据库。

两者都是可能有用的测试。第一个选项更多的是单元测试,并且要求您重构代码以使用依赖注入。然后,您的测试代码将注入某种模拟对象,该对象与您的实际数据库对象具有相同的 API。如果您不熟悉这类事情,谷歌将是您的朋友:单元测试和控制反转在概念上相当简单,但可能有很多细节需要了解。

由于您还没有设置依赖注入,接下来您可以做的就是配置您的测试环境以使用某种测试数据库。这将使它更像是一个集成测试。您可以通过为测试设置不同的数据库来做到这一点,然后(仍然)必须重构代码以根据您的环境调整数据库连接凭据。同样,它在概念上很简单,但可能会丢失很多细节。

如果您不熟悉代码测试,那么值得花一些时间阅读并真正了解它的工作原理。阅读控制反转和单元测试的主题。正确的代码测试对几乎任何代码库来说都是一个巨大的好处,但你真的必须从一开始就做好计划,因为正确的控制反转(这是正确的代码测试所必需的)确实需要以不同的方式组织你的代码。

编辑添加了一些细节:

一旦您计划并执行代码测试,它会变得非常容易,但入门并非易事。最重要的问题是您的代码必须以实际计划未来代码测试的方式编写。在您的情况下,这意味着要么重构代码以使用实际的依赖注入(node.js 支持),要么至少根据环境调整数据库连接。后者会容易得多,但它只允许有限的测试。最后,如果您想进行适当的代码测试,您将不得不重构依赖注入/控制反转。

一旦你这样做了,你的下一步就是选择一个测试框架。我不知道 node.js 的默认设置是什么,但大多数语言/框架都有一个相当标准的,应该不难找到。可能会有不止一种选择,因此您可能会花一些时间选择最适合您风格的一种。选择测试框架后,您必须阅读它的工作原理、设置方法以及使用方法。

一旦你完成了这些事情,你就可以真正开始测试了。第一次做的时候需要做很多工作,但付出 100% 的努力是值得的。

【讨论】:

  • 非常感谢。我正在考虑使用 Mocha 作为测试框架。请问可以举个小例子吗?我在 Internet 上查看过,但我对不同类型的示例感到非常困惑。
  • 恐怕我帮不上忙,因为我不是 node.js 人。希望其他人会提供更多细节,或者您可以在完成 mocha 设置和运行时尝试再次询问更详细的问题。最好的开始是对任何东西进行测试:即使只是一个非常简单的断言:expect('test').to.be.a('string');
【解决方案2】:

您正在做的一些事情存在一些问题,从长远来看,这些问题会使测试成为一个真正的问题。然而,让我们接近最大的罪犯:在你的路由文件中声明你的数据库。这是一个很大的禁忌,它应该只被声明一次并且在需​​要的地方被要求。 pg-promisehere at the official demo 的作者可以找到一个很好的例子。要注意的大事是划分。如果您没有正确设计,那么测试就是您现在遇到的 PITA。但是,如果您正确划分它,当您编写测试时,您可以将模拟对象传递给它,并为其调用方法,这将为您提供一个可测试的环境。

演示中的最大示例:

var options = {
   // Use a custom promise library, instead of the default ES6 Promise:
   promiseLib: promise,
   // Extending the database protocol with our custom repositories:
   extend: obj => {

     // Do not use 'require()' here, because this event occurs for every task
     // and transaction being executed, which should be as fast as possible.
     obj.users = repos.users(obj, pgp);
     obj.products = repos.products(obj, pgp);

     // Alternatively, you can set all repositories in a loop:
     //
     // for (var r in repos) {
     //    obj[r] = repos[r](obj, pgp);
     // }
    }

};

有了这个,您现在可以在 Mocha 中编写简单的模拟(我建议查看 unitjs 的一些示例,但是这样当您将某些东西传递给测试时,您也只需要传递一个带有一个 req 的对象app 对象与pgp 对象与db....你明白了。

所以这里最大的收获是您设计错误(您的代码看起来不错)。您需要将事物重构为单独的部分,以便在进行测试时实际上可以编写有意义的测试。

【讨论】:

    猜你喜欢
    • 2018-08-05
    • 2020-08-19
    • 2015-07-01
    • 2021-05-22
    • 1970-01-01
    • 2021-11-30
    • 2013-11-12
    • 1970-01-01
    • 2015-10-21
    相关资源
    最近更新 更多