gpt4 book ai didi

javascript - 如何连接到 mongoDB 并测试 drop 收集?

转载 作者:行者123 更新时间:2023-12-03 02:41:52 24 4
gpt4 key购买 nike

这就是我使用 monk() 连接到 mongoDB 的方式。我会将其存储在状态中。

假设我们想要删除一些集合,我们调用dropDB

db.js

var state = {
db: null
}

export function connection () {
if (state.db) return
state.db = monk('mongdb://localhost:27017/db')
return state.db
}

export async function dropDB () {
var db = state.db
if (!db) throw Error('Missing database connection')

const Users = db.get('users')
const Content = db.get('content')

await Users.remove({})
await Content.remove({})
}

我不太确定使用state变量是否是一个好方法。也许有人可以对此发表评论或显示改进。

现在我想使用 JestJS 为这个函数编写一个单元测试:

db.test.js

import monk from 'monk'
import { connection, dropDB } from './db'
jest.mock('monk')

describe('dropDB()', () => {
test('should throw error if db connection is missing', async () => {
expect.assertions(1)
await expect(dropDB()).rejects.toEqual(Error('Missing database connection'))
})
})

这部分很简单,但下一部分给我带来了两个问题:

如何模拟 remove() 方法?

  test('should call remove() methods', async () => {
connection() // should set `state.db`, but doesn't work
const remove = jest.fn(() => Promise.resolve({ n: 1, nRemoved: 1, ok: 1 }))
// How do I use this mocked remove()?
expect(remove).toHaveBeenCalledTimes(2)
})

在那之前呢?如何设置state.db

<小时/>

更新

正如poke所解释的那样,全局变量导致了问题。所以我换了一门课:

db.js

export class Db {
constructor() {
this.connection = monk('mongdb://localhost:27017/db');
}

async dropDB() {
const Users = this.connection.get('users');
const Content = this.connection.get('content');

await Users.remove({});
await Content.remove({});
}
}

生成此测试文件:

db.test.js

import { Db } from './db'
jest.mock('./db')

let db
let remove

describe('DB class', () => {
beforeAll(() => {
const remove = jest.fn(() => Promise.resolve({ n: 1, nRemoved: 1, ok: 1 }))
Db.mockImplementation(() => {
return { dropDB: () => {
// Define this.connection.get() and use remove as a result of it
} }
})
})
describe('dropDB()', () => {
test('should call remove method', () => {
db = new Db()
db.dropDB()
expect(remove).toHaveBeenCalledTimes(2)
})
})
})

如何模拟任何 this 元素?在这种情况下,我需要模拟 this.connection.get()

最佳答案

拥有一个全局状态绝对是您问题的根源。我建议寻找一种根本不涉及全局变量的解决方案。根据Global Variables Are Bad ,全局变量会导致紧密耦合并使测试变得困难(正如您自己所注意到的)。

更好的解决方案是将数据库连接显式传递给 dropDB 函数,使其将连接作为显式依赖项,或者引入一些有状态对象它保持连接并提供 dropDB 作为方法。

第一个选项如下所示:

export function openConnection() {
return monk('mongdb://localhost:27017/db');
}

export async function dropDB(connection) {
if (!connection) {
throw Error('Missing database connection');
}

const Users = connection.get('users');
const Content = connection.get('content');

await Users.remove({});
await Content.remove({});
}

这也使得测试 dropDB 变得非常容易,因为您现在可以直接为其传递一个模拟对象。

另一个选项可能如下所示:

export class Connection() {
constructor() {
this.connection = monk('mongdb://localhost:27017/db');
}

async dropDB() {
const Users = this.connection.get('users');
const Content = this.connection.get('content');

await Users.remove({});
await Content.remove({});
}
}
<小时/>

第一个选项的测试可能如下所示:

test('should call remove() methods', async () => {
const usersRemove = jest.fn().mockReturnValue(Promise.resolve(null));
const contentRemove = jest.fn().mockReturnValue(Promise.resolve(null));
const dbMock = {
get(type) {
if (type === 'users') {
return { remove: usersRemove };
}
else if (type === 'content') {
return { remove: contentRemove };
}
}
};

await dropDB(dbMock);

expect(usersRemove).toHaveBeenCalledTimes(1);
expect(contentRemove).toHaveBeenCalledTimes(1);
});

基本上,dropDB 函数需要一个具有 get 方法的对象,该方法在调用时返回一个具有 remove 方法的对象。因此,您只需要传递看起来像这样的东西,以便该函数可以调用那些 remove 方法。

<小时/>

对于该类,这有点复杂,因为构造函数依赖于 monk 模块。一种方法是再次明确该依赖关系(就像在第一个解决方案中一样),并在那里传递 monk 或其他一些工厂。但我们也可以使用Jest’s manual mocks简单地模拟整个 monk 模块。

请注意,我们不想想要模拟包含我们的Connection类型的模块。我们想要测试它,所以我们需要它处于未模拟状态。

要模拟 monk,我们需要在 __mocks__/monk.js 创建它的模拟模块。手册指出这个__mocks__文件夹应该与node_modules文件夹相邻。

在该文件中,我们只需导出自定义 monk 函数。这与我们在第一个示例中使用的几乎相同,因为我们只关心获取这些 remove 方法:

export default function mockedMonk (url) {
return {
get(type) {
if (type === 'users') {
return { remove: mockedMonk.usersRemove };
}
else if (type === 'content') {
return { remove: mockedMonk.contentRemove };
}
}
};
};

请注意,这指的是 mockedMonk.usersRemovemockedMonk.contentRemove 等函数。我们将在测试中使用它在测试执行期间显式配置这些函数。

现在,在测试函数中,我们需要调用 jest.mock('monk') 以使 Jest 能够使用我们的模拟模块来模拟 monk 模块。然后,我们也可以导入它并在测试中设置我们的函数。基本上,就像上面一样:

import { Connection } from './db';
import monk from 'monk';

// enable mock
jest.mock('./monk');

test('should call remove() methods', async () => {
monk.usersRemove = jest.fn().mockReturnValue(Promise.resolve(null));
monk.contentRemove = jest.fn().mockReturnValue(Promise.resolve(null));

const connection = new Connection();
await connection.dropDB();

expect(monk.usersRemove).toHaveBeenCalledTimes(1);
expect(monk.contentRemove).toHaveBeenCalledTimes(1);
});

关于javascript - 如何连接到 mongoDB 并测试 drop 收集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48298414/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com