在node.js中模拟数据库?

Ind*_*ial 70 database unit-testing mocking mongodb node.js

我如何在我的node.js应用程序中模拟出数据库,在这种情况下,它mongodb用作博客REST API的后端?

当然,我可以将数据库设置为特定的testing数据库,但我仍然会保存数据而不是仅测试我的代码,还有数据库,所以我实际上没有进行单元测试而是集成测试.
那应该怎么做?创建数据库包装器作为应用程序和数据库之间的中间层,并在测试时替换DAL?

// app.js  
var express = require('express');
    app = express(),
    mongo = require('mongoskin'),
    db = mongo.db('localhost:27017/test?auto_reconnect');

app.get('/posts/:slug', function(req, res){
    db.collection('posts').findOne({slug: req.params.slug}, function (err, post) {
        res.send(JSON.stringify(post), 200);
    });
});

app.listen(3000);
Run Code Online (Sandbox Code Playgroud)
// test.js
r = require('requestah')(3000);
describe("Does some testing", function() {

  it("Fetches a blogpost by slug", function(done) {
    r.get("/posts/aslug", function(res) {
      expect(res.statusCode).to.equal(200);
      expect(JSON.parse(res.body)["title"]).to.not.equal(null);
      return done();
    });

  });
));
Run Code Online (Sandbox Code Playgroud)

sle*_*man 113

我不认为数据库相关的代码可以在没有用数据库软件测试的情况下进行适当的测试.那是因为您正在测试的代码不仅仅是javascript而且还有数据库查询字符串.即使在您的情况下查询看起来很简单,您也不能永远依赖它.

因此,任何数据库仿真层都必须实现整个数据库(可能减去磁盘存储).到那时,即使您将其称为单元测试,您最终也会使用数据库模拟器进行集成测试.另一个缺点是,数据库模拟器最终可能有一组不同的错误相比,数据库,你可能最终不得不代码为两个数据库仿真器和数据库(有点像用IE的形势与火狐浏览器VS等).

因此,在我看来,正确测试代码的唯一方法是将其与真实数据库连接.

  • @MichaelPerrenoud:我喜欢christkv的答案所规定的规则:**"不要嘲笑你不拥有的任何东西"**.虽然它没有详细说明为什么这是一个坏主意,但这是一个容易记住的规则. (4认同)
  • 我不同意这个答案,在meteorjs中,他们在运行测试时以某种方式设置了一个测试数据库(我认为它不是一个模拟库,而是一个临时文件),而且非常方便。如果对象的行为与 mongodb 完全相同并且会自行清理,那将非常有用。无论是全部在内存中还是临时文件中都是实现细节,因此您不必重复代码。我确实同意,制作驱动程序的人应该是制作模拟对象的人。 (2认同)
  • 看,嘲笑数据库调用是非常愚蠢的,只会导致繁忙的工作。我认为人们错过了测试的全部意义。这是为了表明输入匹配输出。对于调用 DB 的函数,除非该测试涉及 db 调用,否则您无法确定。最好的方法是让您的测试配置指向在内存上运行的 MongoDB 实例。这样您就不必处理磁盘 I/O,而且还实现了“模拟”的主要目的,即从内存中运行。 (2认同)

小智 40

当涉及到嘲弄时,有一般的经验法则

不要嘲笑你不拥有的任何东西.

如果你想模拟数据库隐藏它,那么就会破坏抽象的服务层并模拟该层.然后确保集成测试实际的服务层.

就个人而言,我已经不再使用模拟进行测试,而是使用它们进行自上而下的设计,帮助我从顶部到底部驱动开发模拟服务层,然后最终实现这些层并编写集成测试.作为测试工具,它们往往会使您的测试变得非常脆弱,在最坏的情况下会导致实际行为与模拟行为之间的差异.


Pos*_*Guy 38

到目前为止,我不同意所选答案或其他答复.

如果您能够捕获由混乱而产生的错误,并且在进行QA之前对DB模式和代码进行多次混乱更改,那会不会很棒?我敢打赌,大多数人会大声喊出来!

您当然可以而且应该隔离并测试数据库模式.而且你不是基于模拟器或重型图像或数据库和机器的重新创建它.这就像SQLite之类的东西就是一个例子.您可以根据内存中的轻量级实例和内存实例中没有更改的静态数据来模拟它,这意味着您真正独立地测试数据库,并且您也可以信任您的测试.显然它很快,因为它在内存中,一个骨架,并在测试运行结束时被废弃.

所以是的,您应该测试导出到您正在使用的任何数据库引擎/运行时的非常轻量级内存实例中的SCHEMA,并且添加非常少量的静态数据将成为您孤立的模拟数据库.

您可以定期(以自动方式)从真实数据库中导出真实模式,并在每次推送到QA之前将其导入/更新到内存数据库实例中,并且您将立即知道数据库管理员或其他人是否进行了任何最新数据库更改最近更改了架构的开发人员已经破坏了任何测试.

虽然我赞赏尽力回答的努力,如果可以的话,我会对当前的答案进行投票,但我是新人并且还没有建立足够的声誉,但我还没有能力做到这一点.

至于回答"不要嘲笑你不拥有的东西"的人.我想他的意思是"不要测试你不拥有的东西".但你要嘲笑你不拥有的东西!因为那些是未经测试的东西需要被隔离!

我计划与你分享HOW,并将在未来的时间点使用真实的JS代码更新这篇文章!

这是许多测试驱动的团队一直在做的事情.你只需要了解方法.

  • 我很乐意投票,但如果它没有缓解问题并提供解决方案我就不能.如果有机会请更新您的帖子. (3认同)
  • 从 3 年开始,我已经投了反对票,但仍然没有如何。 (3认同)
  • 2018年仍然没有“如何做”,当然有兴趣阅读更多。 (2认同)

cir*_*rus 5

我对任何语言的单元测试 DB 代码的首选方法是通过存储库抽象访问 Mongo(这里有一个示例http://iainjmitchell.com/blog/?p=884)。实现将因公开的特定于 DB 的功能而异,但通过从您自己的逻辑中删除所有 Mongo 代码,您就可以进行单元测试。只需将 Mongo Repository 实现替换为一个非常简单的存根版本。例如,只需将对象存储在一个简单的内存字典集合中。

您将获得以这种方式对您自己的代码进行单元测试而不依赖于数据库的好处,但您仍然需要对主数据库进行集成测试,因为您可能永远无法像其他人那样模拟真实数据库的特性说到这里。我发现的事情就像在安全模式下与没有安全模式下索引一样简单。具体来说,如果你有一个唯一的索引,你的虚拟内存实现可能会在所有情况下都遵守这一点,但 Mongo 不会没有安全模式。

因此,虽然您仍然需要针对某些操作对数据库进行测试,但您当然可以使用存根存储库实现正确地对自己的逻辑进行单元测试。


Mic*_*ole 5

模拟的目的是跳过复杂性并对自己的代码进行单元测试。如果您想编写 e2e 测试,请使用 db.

编写代码来设置/拆卸测试数据库以进行单元测试是技术债务,并且令人难以置信地不满意。

npm 中有模拟库:

mongo - https://www.npmjs.com/package/mongomock

猫鼬 - https://www.npmjs.com/package/mockgoose

如果这些不支持您需要的功能,那么您可能需要使用真实的东西。