简体   繁体   English

在 node.js 中模拟数据库?

[英]Mocking database in node.js?

How would I mock out the database in my node.js application, which in this case uses mongodb as the backend for a blog REST API ?我将如何在我的 node.js 应用程序中模拟数据库,在这种情况下,它使用mongodb作为博客 REST API 的后端?

Sure, I could set the database to a specific testing -database, but I would still save data and not test my code only, but also the database, so I am actually not doing unit testing but integration testing.当然,我可以将数据库设置为特定的testing数据库,但我仍然会保存数据,不仅测试我的代码,还测试数据库,所以我实际上不是在做单元测试而是集成测试。
So what should one do?那么应该怎么做呢? Create database wrappers as a middle layer between application and db and replace the DAL when in 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);

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

  });
));

I don't think database related code can be properly tested without testing it with the database software.我认为如果不使用数据库软件对其进行测试,就无法正确测试与数据库相关的代码。 That's because the code you're testing is not just javascript but also the database query string.那是因为您正在测试的代码不仅是 javascript,还包括数据库查询字符串。 Even though in your case the queries look simple you can't rely on it being that way forever.即使在您的情况下,查询看起来很简单,您也不能永远依赖它。

So any database emulation layer will necessarily implement the entire database (minus disk storage perhaps).因此,任何数据库仿真层都必须实现整个数据库(可能减去磁盘存储)。 By then you end up doing integration testing with the database emulator even though you call it unit testing.到那时,您最终会使用数据库模拟器进行集成测试,即使您将其称为单元测试。 Another downside is that the database emulator may end up having a different set of bugs compared to the database and you may end up having to code for both the database emulator and the database (kind of like the situation with IE vs Firefox vs Chrome etc.).另一个缺点是,与数据库相比,数据库模拟器最终可能会出现一组不同的错误,您可能最终不得不为数据库模拟器和数据库编写代码(有点像 IE 与 Firefox 与 Chrome 等的情况。 )。

Therefore, in my opinion, the only way to correctly test your code is to interface it with the real database.因此,在我看来,正确测试代码的唯一方法是将其与真实数据库连接。

There is a general rule of thumb when it comes to mocking which is在嘲笑方面有一个一般的经验法则,即

Don't mock anything you don't own.不要嘲笑你不拥有的任何东西。

If you want to mock out the database hide it behind an abstracted service layer and mock that layer.如果您想模拟数据库,请将其隐藏在抽象服务层之后并模拟该层。 Then make sure you integration test the actual service layer.然后确保您对实际服务层进行集成测试。

Personally I've gone away from using mocks for testing and use them for top-to-bottom design helping me drive development from the top towards the bottom mocking out service layers as I go and then eventually implementing those layers and writing integration tests.就我个人而言,我已经不再使用模拟进行测试,而是将它们用于自上而下的设计,帮助我从上到下推动开发,在我进行时模拟服务层,然后最终实现这些层并编写集成测试。 Used as a test tool they tend to make your test very brittle and in the worst case leads to a divergence between actual behavior and mocked behavior.用作测试工具时,它们往往会使您的测试变得非常脆弱,在最坏的情况下会导致实际行为和模拟行为之间出现分歧。

I don't agree with the selected answer or other replies so far.到目前为止,我不同意所选的答案或其他回复。

Wouldn't it be awesome if you could catch errors spawned by the chaotic and many times messy changes made to DB schemas and your code BEFORE it gets to QA?如果您能够在进入 QA 之前捕获由对 DB 模式和您的代码所做的混乱且多次凌乱的更改所产生的错误,那不是很棒吗? I bet the majority would shout heck yes!我打赌大多数人会大喊是的!

You most certainly can and should isolate and test you DB schemas.您当然可以而且应该隔离和测试您的数据库模式。 And you don't do it based on an emulator or heavy image or recreation of you DB and machine.而且您不是基于模拟器或繁重的图像或对您的数据库和机器进行重新创建。 This is what stuff like SQLite is for just as one example.这就是像 SQLite 这样的东西作为一个例子。 You mock it based on an in memory lightweight instance running and with static data that does not change in that in memory instance which means you are truly testing your DB in isolation and you can trust your tests as well.您基于内存中轻量级实例运行并使用在内存实例中不会更改的静态数据来模拟它,这意味着您真正独立地测试了您的数据库,并且您也可以信任您的测试。 And obviously it's fast because it's in memory, a skeleton, and is scrapped at the end of a test run.显然它很快,因为它在内存中,是一个骨架,并在测试运行结束时被废弃。

So yes you should and you should test the SCHEMA that is exported into a very lightweight in memory instance of whatever DB engine/runtime you are using, and that along with adding a very small amount of static data becomes your isolated mocked DB.所以是的,您应该并且应该测试导出到您正在使用的任何数据库引擎/运行时的非常轻量级的内存实例中的 SCHEMA,并且随着添加非常少量的静态数据成为您隔离的模拟数据库。

You export your real schemas from your real DB periodically (in an automated fashion) and import/update those into your light in memory DB instance before every push to QA and you will know instantly if any latest DB changes done by your DB admins or other developers who have changed the schema lately have broken any tests .您定期(以自动方式)从真实数据库中导出真实模式,并在每次推送到 QA 之前将这些模式导入/更新到您的内存数据库实例中,您将立即知道您的数据库管理员或其他人是否进行了任何最新的数据库更改最近更改架构的开发人员破坏了所有测试。

While I applaud the effort to try your best to answer I would down-vote the current answer if I could but I am new and have not built up enough reputation yet to enable my ability to do so yet.虽然我对尽力回答的努力表示赞赏,但如果可以的话,我会否决当前的答案,但我是新手,还没有建立足够的声誉来使我有能力这样做。

As for the person who replied with the "don't mock anything you don't own".至于回答“不要嘲笑任何你不拥有的东西”的人。 I think he meant to say "don't test anything you don't own".我认为他的意思是“不要测试你不拥有的任何东西”。 But you DO mock things you do not own!但是你确实嘲笑你不拥有的东西! Because those are the things not under test that need to be isolated!因为那些是没有被测试的东西需要被隔离!

I plan on sharing the HOW with you and will update this post in a future point in time with real example JS code!我计划与您分享 HOW,并将在未来的某个时间点使用真实的示例 JS 代码更新这篇文章!

This is what many test driven teams do all the time.这是许多测试驱动团队一直在做的事情。 You just have to understand the how.你只需要了解如何。

My preferred approach to unit test DB code in any language is to access Mongo through a Repository abstraction (there's an example here http://iainjmitchell.com/blog/?p=884 ).我对任何语言的单元测试 DB 代码的首选方法是通过存储库抽象访问 Mongo(这里有一个示例http://iainjmitchell.com/blog/?p=884 )。 Implementations will vary in terms of DB specific functionality exposed but by removing all the Mongo code from your own logic you're in a position to Unit Test.实现将因公开的特定于 DB 的功能而异,但通过从您自己的逻辑中删除所有 Mongo 代码,您就可以进行单元测试。 Simply replace the Mongo Repository implementation with a stubbed out version which is trivially easy.只需将 Mongo Repository 实现替换为一个非常简单的存根版本。 For instance, just store objects in a simple in-memory dictionary collection.例如,只需将对象存储在一个简单的内存字典集合中。

You'll get the benefits of unit testing your own code this way without DB dependencies but you'll still need to do integration tests against the main DB because you'll probably never be able to emulate the idiosyncrasies of the real database as others have said here.您将获得以这种方式对您自己的代码进行单元测试而不依赖于数据库的好处,但您仍然需要对主数据库进行集成测试,因为您可能永远无法像其他人那样模拟真实数据库的特性说到这里。 The kind of things I've found are as simple as indexing in safe mode vs without safe mode.我发现的事情就像在安全模式下与没有安全模式下索引一样简单。 Specifically, if you have a unique index your dummy memory implementation might honour that in all cases, but Mongo won't without safe-mode.具体来说,如果你有一个唯一的索引,你的虚拟内存实现可能会在所有情况下都遵守这一点,但 Mongo 不会没有安全模式。

So whilst you'll still need to test against the DB for some operations, you'll certainly be able to unit test your own logic properly with a stubbed out Repository implementation.因此,虽然您仍然需要针对某些操作对数据库进行测试,但您当然可以使用存根存储库实现正确地对自己的逻辑进行单元测试。

The purpose of mocking is to skip the complexity and unit test own code.模拟的目的是跳过复杂性和单元测试自己的代码。 If you want to write e2e tests then use the db.如果要编写 e2e 测试,请使用 db.

Writing code to setup/teardown a testing DB for unit testing is technical debt and incredibly unsatisfying.编写代码来设置/拆除用于单元测试的测试数据库是技术债务,并且令人难以置信地不令人满意。

There are mock libraries in npm: npm 中有模拟库:

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

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

If those don't support the features you need, then yes you may need to use the real thing.如果那些不支持您需要的功能,那么是的,您可能需要使用真实的东西。

I had this dilemma and chosen to work with a test DB and clean it every time the test begins.我遇到了这个困境,并选择使用测试数据库并在每次测试开始时对其进行清理。 (how to drop everything: https://stackoverflow.com/a/25639377/378594 ) (如何删除所有内容: https : //stackoverflow.com/a/25639377/378594

With NPM you can even make a test script that creates the db file and cleans it up after.使用 NPM,您甚至可以制作一个测试脚本来创建 db 文件并在之后对其进行清理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM