- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我已经尝试创建一个类来连接到 mongoDB(并使用 (gridfs-stream
) 获得 gridFS 连接)。但是我确实遇到了两个问题:
server instance in invalid state connected
所以如果有人可以帮助我优化这个类以获得一个真正扎实的工作类,我将非常感激。例如,我不喜欢 connect() 函数中的 let that = this
。
数据库类
const mongo = require('mongodb')
const Grid = require('gridfs-stream')
const { promisify } = require('util')
export default class Db {
constructor (uri, callback) {
this.db = null
this.gfs = null
const server = process.env.MONGO_SERVER || 'localhost'
const port = process.env.MONGO_PORT || 27017
const db = process.env.MONGO_DB || 'test'
// Is this the correct way to connect (using mongo native driver)?
this.connection = new mongo.Db(db, new mongo.Server(server, port))
this.connection.open = promisify(this.connection.open)
this.connected = false
return this
}
async connect (msg) {
let that = this
if (!this.db) {
try {
await that.connection.open()
that.gfs = Grid(that.connection, mongo)
this.connected = true
} catch (err) {
console.error('mongo connection error', err)
}
}
return this
}
isConnected () {
return this.connected
}
}
示例
此函数将使用上面的类向数据库添加一个新用户:
import bcrypt from 'bcrypt'
import Db from './lib/db'
const db = new Db()
export async function createUser (obj, { username, password }) {
if (!db.isConnected()) await db.connect()
const Users = db.connection.collection('users')
return Users.insert({
username,
password: bcrypt.hashSync(password, 10),
createdAt: new Date()
})
}
单元测试
我需要创建一个单元测试来测试是否调用了 mongoDB 方法。没有用于测试该方法的集成测试。所以我需要模拟数据库连接、收集和插入方法。
import bcrypt from 'bcrypt'
import { createUser } from '../../user'
import Db from '../../lib/db'
const db = new Db()
jest.mock('bcrypt')
describe('createUser()', () => {
test('should call mongoDB insert()', async () => {
bcrypt.hashSync = jest.fn(() => SAMPLE.BCRYPT)
// create somekind of mock for the insert method...
db.usersInsert = jest.fn(() => Promise.resolve({ _id: '507f1f77bcf86cd799439011' }))
await createUser({}, {
username: 'username',
password: 'password'
}).then((res) => {
// test if mocked insert method has been called
expect(db.usersInsert).toHaveBeenCalled()
// ... or better test for the returned promise value
})
})
})
最佳答案
有多种方法可以解决这个问题。我将列出其中的一些
我将在此处展示第一个案例,您发布了该案例以及代码以及如何使其发挥作用。所以我们要做的第一件事是更新 __mocks__/db.js
文件到下面
jest.mock('mongodb');
const mongo = require('mongodb')
var mock_collections = {};
var connectError = false;
var connected = false;
export default class Db {
constructor(uri, callback) {
this.__connectError = (fail) => {
connected = false;
connectError = fail;
};
this.clearMocks = () => {
mock_collections = {};
connected = false;
};
this.connect = () => {
return new Promise((resolve, reject) => {
process.nextTick(
() => {
if (connectError)
reject(new Error("Failed to connect"));
else {
resolve(true);
this.connected = true;
}
}
);
});
};
this.isConnected = () => connected;
this.connection = {
collection: (name) => {
mock_collections[name] = mock_collections[name] || {
__collection: name,
insert: jest.fn().mockImplementation((data) => {
const ObjectID = require.requireActual('mongodb').ObjectID;
let new_data = Object.assign({}, {
_id: new ObjectID()
},data);
return new Promise((resolve, reject) => {
process.nextTick(
() =>
resolve(new_data))
}
);
})
,
update: jest.fn(),
insertOne: jest.fn(),
updateOne: jest.fn(),
};
return mock_collections[name];
}
}
}
}
现在很少解释
jest.mock('mongodb');
将确保任何实际的 mongodb 调用都被模拟connected
, connectError
, mock_collections
是全局变量。这样我们就可以影响 Db
的状态你的user.js
负载。如果我们不这样做,我们将无法控制模拟的 Db
。来 self 们的测试this.connect
展示了如何返回一个 promise ,以及如何在需要时模拟连接到数据库的错误collection: (name) => {
确保您调用 createUser
并且您的测试可以获得相同的集合接口(interface)并检查是否实际调用了模拟函数。insert: jest.fn().mockImplementation((data) => {
展示如何通过创建自己的实现来返回数据const ObjectID = require.requireActual('mongodb').ObjectID;
展示了在模拟 mongodb
后如何获得实际的模块对象早些时候现在是测试部分。这是更新的 user.test.js
jest.mock('../../lib/db');
import Db from '../../lib/db'
import { createUser } from '../../user'
const db = new Db()
describe('createUser()', () => {
beforeEach(()=> {db.clearMocks();})
test('should call mongoDB insert() and update() methods 2', async () => {
let User = db.connection.collection('users');
let user = await createUser({}, {
username: 'username',
password: 'password'
});
console.log(user);
expect(User.insert).toHaveBeenCalled()
})
test('Connection failure', async () => {
db.__connectError(true);
let ex = null;
try {
await createUser({}, {
username: 'username',
password: 'password'
})
} catch (err) {
ex= err;
}
expect(ex).not.toBeNull();
expect(ex.message).toBe("Failed to connect");
})
})
再次提出几点建议
jest.mock('../../lib/db');
将确保加载我们的手动模拟let user = await createUser({}, {
因为你正在使用 async
, 你不会使用 then
或 catch
.这就是使用 async
的意义所在功能。 db.__connectError(true);
将设置全局变量 connected
至 false
和 connectError
为真。所以当createUser
在测试中被调用它将模拟连接错误ex= err;
,看看我是如何捕获异常并取出 expect 调用的。如果您确实希望在 catch
block 本身,那么当没有引发异常时,测试仍然会通过。这就是为什么我在 try/catch
之外进行异常测试的原因阻止现在是通过运行 npm test
对其进行测试的部分我们得到
所有这些都提交给您共享的以下 repo
关于javascript - 如何创建一个可模拟的类来连接到 mongoDB?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49345702/
前言: 有时候,一个数据库有多个帐号,包括数据库管理员,开发人员,运维支撑人员等,可能有很多帐号都有比较大的权限,例如DDL操作权限(创建,修改,删除存储过程,创建,修改,删除表等),账户多了,管理
所以我用 Create React App 创建并设置了一个大型 React 应用程序。最近我们开始使用 Storybook 来处理和创建组件。它很棒。但是,当我们尝试运行或构建应用程序时,我们不断遇
遵循我正在创建的控件的代码片段。这个控件用在不同的地方,变量也不同。 我正在尝试编写指令来清理代码,但在 {{}} 附近插入值时出现解析错误。 刚接触 Angular ,无法确定我错过了什么。请帮忙。
我正在尝试创建一个 image/jpeg jax-rs 提供程序类,它为我的基于 post rest 的 Web 服务创建一个图像。我无法制定请求来测试以下内容,最简单的测试方法是什么? @POST
我一直在 Windows 10 的模拟器中练习 c。后来我改用dev C++ IDE。当我在 C 中使用 FILE 时。创建的文件的名称为 test.txt ,而我给出了其他名称。请帮助解决它。 下面
当我们创建自定义 View 时,我们将 View 文件的所有者设置为自定义类,并使用 initWithFrame 或 initWithCode 对其进行实例化。 当我们创建 customUITable
我正在尝试为函数 * Producer 创建一个线程,但用于创建线程的行显示错误。我为这句话加了星标,但我无法弄清楚它出了什么问题...... #include #include #include
今天在做项目时,遇到了需要创建JavaScript对象的情况。所以Bing了一篇老外写的关于3种创建JavaScript对象的文章,看后跟着打了一遍代码。感觉方法挺好的,在这里与大家分享一下。 &
我正在阅读将查询字符串传递给 Amazon 的 S3 以进行身份验证的文档,但似乎无法理解 StringToSign 的创建和使用方式。我正在寻找一个具体示例来说明 (1) 如何构造 String
前言:我对 C# 中任务的底层实现不太了解,只了解它们的用法。为我在下面屠宰的任何东西道歉: 对于“我怎样才能开始一项任务但不等待它?”这个问题,我找不到一个好的答案。在 C# 中。更具体地说,即使任
我有一个由一些复杂的表达式生成的 ILookup。假设这是按姓氏查找人。 (在我们简单的世界模型中,姓氏在家庭中是唯一的) ILookup families; 现在我有两个对如何构建感兴趣的查询。 首
我试图创建一个 MSI,其中包含 和 exe。在 WIX 中使用了捆绑选项。这样做时出错。有人可以帮我解决这个问题。下面是代码: 错误 error LGH
在 Yii 中,Create 和 Update 通常使用相同的形式。因此,如果我在创建期间有电子邮件、密码、...other_fields...等字段,但我不想在更新期间专门显示电子邮件和密码字段,但
上周我一直在努力创建一个给定一行和一列的 QModelIndex。 或者,我会满足于在已经存在的 QModelIndex 中更改 row() 的值。 任何帮助,将不胜感激。 编辑: QModelInd
出于某种原因,这不起作用: const char * str_reset_command = "\r\nReset"; const char * str_config_command = "\r\nC
现在,我有以下由 original.df %.% group_by(Category) %.% tally() %.% arrange(desc(n)) 创建的 data.frame。 DF 5),
在今天之前,我使用/etc/vim/vimrc来配置我的vim设置。今天,我想到了创建.vimrc文件。所以,我用 touch .vimrc cat /etc/vim/vimrc > .vimrc 所
我可以创建一个 MKAnnotation,还是只读的?我有坐标,但我发现使用 setCooperative 手动创建 MKAnnotation 并不容易。 想法? 最佳答案 MKAnnotation
在以下代码中,第一个日志语句按预期显示小数,但第二个日志语句记录 NULL。我做错了什么? NSDictionary *entry = [[NSDictionary alloc] initWithOb
我正在使用与此类似的代码动态添加到数组; $arrayF[$f+1][$y][$x+1] = $value+1; 但是我在错误报告中收到了这个: undefined offset :1 问题:尝试创
我是一名优秀的程序员,十分优秀!