- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
给定一个简单的 Mongoose 模型:
import mongoose, { Schema } from 'mongoose';
const PostSchema = Schema({
title: { type: String },
postDate: { type: Date, default: Date.now }
}, { timestamps: true });
const Post = mongoose.model('Post', PostSchema);
export default Post;
import mongoose from 'mongoose';
import { expect } from 'chai';
import { Post } from '../../app/models';
describe('Post', () => {
beforeEach((done) => {
mongoose.connect('mongodb://localhost/node-test');
done();
});
describe('Given a valid post', () => {
it('should create the post', (done) => {
const post = new Post({
title: 'My test post',
postDate: Date.now()
});
post.save((err, doc) => {
expect(doc.title).to.equal(post.title)
expect(doc.postDate).to.equal(post.postDate);
done();
});
});
});
});
import mockgoose from 'mockgoose';
// in before or beforeEach
mockgoose(mongoose);
Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
我试过将超时增加到 20 秒,但这并没有解决任何问题。
save
称呼。
describe('Given a valid post', () => {
it('should create the post', (done) => {
const post = new Post({
title: 'My test post',
postDate: Date.now()
});
const stub = sinon.stub(post, 'save', function(cb) { cb(null) })
post.save((err, post) => {
expect(stub).to.have.been.called;
done();
});
});
});
save
方法在
post
,然后我断言它已被调用,但我显然是在调用它...此外,我似乎无法获得非 stub Mongoose 方法将返回的参数。我想比较
post
变量
save
方法返回,就像在我访问数据库的第一个测试中一样。我试过
couple的
methods但他们都觉得很hackish。必须有一个干净的方式,不是吗?
最佳答案
基础知识
在单元测试中,不应击中 DB。我可以想到一个异常(exception):访问内存数据库,但即使这已经存在于集成测试领域,因为您只需要为复杂进程保存在内存中的状态(因此不是真正的功能单元)。所以,是的,没有实际的数据库。
您想要在单元测试中测试的是您的业务逻辑会在您的应用程序和数据库之间的接口(interface)上产生正确的 API 调用。您可以并且可能应该假设 DB API/驱动程序开发人员已经很好地测试了 API 下的所有内容都按预期运行。但是,您还希望在测试中涵盖您的业务逻辑如何对不同的有效 API 结果使用react,例如成功保存、由于数据一致性导致的失败、由于连接问题导致的失败等。
这意味着您需要并想要模拟的是 DB 驱动程序接口(interface)下方的所有内容。但是,您需要对该行为进行建模,以便可以针对 DB 调用的所有结果测试您的业务逻辑。
说起来容易做起来难,因为这意味着您需要通过您使用的技术访问 API,并且您需要了解 API。
Mongoose 的现实
坚持基础知识,我们想模拟 mongoose 使用的底层“驱动程序”执行的调用。假设它是 node-mongodb-native我们需要模拟这些调用。了解 mongoose 和 native 驱动程序之间的完整交互并不容易,但通常归结为 mongoose.Collection
中的方法。因为后者扩展 mongoldb.Collection
并且不会重新实现类似 insert
的方法.如果我们能够控制 insert
的行为在这种特殊情况下,我们知道我们在 API 级别模拟了数据库访问。您可以在两个项目的源代码中对其进行跟踪,即 Collection.insert
是真正的 native 驱动程序方法。
对于您的特定示例,我创建了 a public Git repository有一个完整的包,但我会在答案中发布所有元素。
解决方案
就我个人而言,我发现使用 mongoose 的“推荐”方式非常不可用:模型通常在定义相应模式的模块中创建,但它们已经需要连接。为了让多个连接与同一项目中完全不同的 mongodb 数据库进行通信以及出于测试目的,这让生活变得非常艰难。事实上,一旦顾虑完全分离, Mongoose 就几乎无法使用,至少对我而言。
所以我创建的第一件事是包描述文件,一个带有模式和通用“模型生成器”的模块:
package.json
{
"name": "xxx",
"version": "0.1.0",
"private": true,
"main": "./src",
"scripts": {
"test" : "mocha --recursive"
},
"dependencies": {
"mongoose": "*"
},
"devDependencies": {
"mocha": "*",
"chai": "*"
}
}
src/post.js
var mongoose = require("mongoose");
var PostSchema = new mongoose.Schema({
title: { type: String },
postDate: { type: Date, default: Date.now }
}, {
timestamps: true
});
module.exports = PostSchema;
src/index.js
var model = function(conn, schema, name) {
var res = conn.models[name];
return res || conn.model.bind(conn)(name, schema);
};
module.exports = {
PostSchema: require("./post"),
model: model
};
post
在内心深处创造。
test/mock.js
var mongoose = require("mongoose");
// this method is propagated from node-mongodb-native
mongoose.Collection.prototype.insert = function(docs, options, callback) {
// this is what the API would do if the save succeeds!
callback(null, docs);
};
module.exports = mongoose;
Post
特有的模型,并且可以为所有其他模型完成,并且具有完全相同的模拟。
test/test_model.js
// now we have mongoose with the mocked API
// but it is essential that our models are created AFTER
// the API was mocked, not in the main source!
var mongoose = require("./mock"),
assert = require("assert");
var underTest = require("../src");
describe("Post", function() {
var Post;
beforeEach(function(done) {
var conn = mongoose.createConnection();
Post = underTest.model(conn, underTest.PostSchema, "Post");
done();
});
it("given valid data post.save returns saved document", function(done) {
var post = new Post({
title: 'My test post',
postDate: Date.now()
});
post.save(function(err, doc) {
assert.deepEqual(doc, post);
done(err);
});
});
it("given valid data Post.create returns saved documents", function(done) {
var post = new Post({
title: 'My test post',
postDate: 876543
});
var posts = [ post ];
Post.create(posts, function(err, docs) {
try {
assert.equal(1, docs.length);
var doc = docs[0];
assert.equal(post.title, doc.title);
assert.equal(post.date, doc.date);
assert.ok(doc._id);
assert.ok(doc.createdAt);
assert.ok(doc.updatedAt);
} catch (ex) {
err = ex;
}
done(err);
});
});
it("Post.create filters out invalid data", function(done) {
var post = new Post({
foo: 'Some foo string',
postDate: 876543
});
var posts = [ post ];
Post.create(posts, function(err, docs) {
try {
assert.equal(1, docs.length);
var doc = docs[0];
assert.equal(undefined, doc.title);
assert.equal(undefined, doc.foo);
assert.equal(post.date, doc.date);
assert.ok(doc._id);
assert.ok(doc.createdAt);
assert.ok(doc.updatedAt);
} catch (ex) {
err = ex;
}
done(err);
});
});
});
Post.create
的任何业务逻辑。或
post.save
内部。
~/source/web/xxx $ npm test
> xxx@0.1.0 test /Users/osklyar/source/web/xxx
> mocha --recursive
Post
✓ given valid data post.save returns saved document
✓ given valid data Post.create returns saved documents
✓ Post.create filters out invalid data
3 passing (52ms)
关于node.js - Mocking/stubbing Mongoose 模型保存方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33270667/
我尝试根据表单元素的更改禁用/启用保存按钮。但是,当通过弹出按钮选择更改隐藏输入字段值时,保存按钮不受影响。 下面是我的代码。我正在尝试序列化旧的表单值并与更改后的表单值进行比较。但我猜隐藏的字段值无
我正在尝试保存模型的实例,但我得到了 Invalid EmbeddedDocumentField item (1) 其中 1 是项目的 ID(我认为)。 模型定义为 class Graph(Docum
我有一个非常奇怪的问题......在我的 iPhone 应用程序中,用户可以打开相机胶卷中的图像,在我的示例中 1920 x 1080 像素 (72 dpi) 的壁纸。 现在,想要将图像的宽度调整为例
目前,我正在使用具有排序/过滤功能的数据表成功地从我的数据库中显示图像元数据。在我的数据表下方,我使用第三方图像覆盖流( http://www.jacksasylum.eu/ContentFlow/
我的脚本有问题。我想按此顺序执行以下步骤: 1. 保存输入字段中的文本。 2. 删除输入字段中的所有文本。 3. 在输入字段中重新加载之前删除的相同文本。 我的脚本的问题是 ug()- 函数在我的文本
任何人都可以帮助我如何保存多对多关系吗?我有任务,用户可以有很多任务,任务可以有很多用户(多对多),我想要实现的是,在更新表单中,管理员可以将多个用户分配给特定任务。这是通过 html 多选输入来完成
我在 Tensorflow 中训练了一个具有批归一化的模型。我想保存模型并恢复它以供进一步使用。批量归一化是通过 完成的 def batch_norm(input, phase): retur
我遇到了 grails 的问题。我有一个看起来像这样的域: class Book { static belongsTo = Author String toString() { tit
所以我正在开发一个应用程序,一旦用户连接(通过 soundcloud),就会出现以下对象: {userid: userid, username: username, genre: genre, fol
我正在开发一个具有多选项卡布局的 Angular 7 应用程序。每个选项卡都包含一个组件,该组件可以引用其他嵌套组件。 当用户选择一个新的/另一个选项卡时,当前选项卡上显示的组件将被销毁(我不仅仅是隐
我尝试使用 JEditorPane 进行一些简单的文本格式化,但随着知识的增长,我发现 JTextPane 更容易实现并且更强大。 我的问题是如何将 JTextPane 中的格式化文本保存到文件?它应
使用 Docker 相当新。 我为 Oracle 11g Full 提取了一个图像。创建了一个数据库并将应用程序安装到容器中。 正确配置后,我提交了生成 15GB 镜像的容器。 测试了该图像的新容器,
我是使用 Xcode 和 swift 的新手,仍在学习中。我在将核心数据从实体传递到文本字段/标签时遇到问题,然后用户可以选择编辑和保存记录。我的目标是,当用户从 friendslistViewCon
我正在用 Java 编写 Android 游戏,我需要一种可靠的方法来快速保存和加载应用程序状态。这个问题似乎适用于大多数 OO 语言。 了解我需要保存的内容:我正在使用策略模式来控制我的游戏实体。我
我想知道使用 fstream 加载/保存某种结构类型的数组是否是个好主意。注意,我说的是加载/保存到二进制文件。我应该加载/保存独立变量,例如 int、float、boolean 而不是结构吗?我这么
我希望能够将 QNetworkReply 保存到 QString/QByteArray。在我看到的示例中,它们总是将流保存到另一个文件。 目前我的代码看起来像这样,我从主机那里得到一个字符串,我想做的
我正在创建一个绘图应用程序。我有一个带有 Canvas 的自定义 View ,它根据用户输入绘制线条: class Line { float startX, startY, stopX, stop
我有 3 个 Activity 第一个 Activity 调用第二个 Activity ,第二个 Activity 调用第三个 Activity 。 第二个 Activity 使用第一个 Activi
我想知道如何在 Xcode 中保存 cookie。我想使用从一个网页获取的 cookie 并使用它访问另一个网页。我使用下面的代码登录该网站,我想保存从该连接获得的 cookie,以便在我建立另一个连
我有一个 SQLite 数据库存储我的所有日历事件,建模如下: TimerEvent *Attributes -date -dateForMark -reminder *Relat
我是一名优秀的程序员,十分优秀!