尝试测试如下所示的代码:
const mysql = require('mysql2/promise');
async myFunction () {
const db = await mysql.createConnection(options);
const results = await db.execute('SELECT `something` from `table`;');
await db.end();
// more code ...
}
我需要以一种允许我使用它返回的任何内容来模拟对 execute
的调用的方式来模拟 mysql 连接。功能。我试过 mock 整个
mysql2/promise
模块,但当然这不起作用,因为被 mock 的 createConnection
没有返回任何可以调用 execute
的东西功能。我还尝试只模拟我需要的这 3 个函数,而不是模拟整个模块,例如:
jest.mock('mysql2/promise', () => ({
createConnection: jest.fn(() => ({
execute: jest.fn(),
end: jest.fn(),
})),
}));
但这也不起作用。任何建议都非常感谢。
最佳答案
我会以不同的方式处理这个问题。当你觉得你需要模拟整个第三方库进行测试时,你的应用程序中出现了一些问题。
作为一般的最佳实践,您应该始终包装第三方库。退房 this discussion对于初学者。
基本上的想法是定义您自己的接口(interface)到所需的功能,然后使用第三方库实现这些接口(interface)。在您的其余代码中,您将只针对接口(interface)工作,而不是针对第三方实现。
这有几个优点
那么这怎么可能呢?
首先,定义一个接口(interface),因为它在您的代码中最有用。也许,您的数据库接口(interface)可能如下所示:
interface Database<T> {
create(object: T): Promise<void>;
get(id: string): Promise<T>;
getAll(): Promise<T[]>;
update(id: string, object: T): Promise<void>;
delete(id: string): Promise<void>;
}
现在,您可以针对此开发您的整个代码库 Database
界面。当您需要从“表”中检索数据时,您可以使用 Database
,而不是在整个代码中编写 MySQL 查询。执行。我就举个例子
ResultRetriever
这里很原始,但达到了目的:class ResultRetriever {
constructor(private database: Database<Something>) {}
getResults(): Promise<Something[]> {
return this.database.getAll();
}
}
如您所见,您的代码不需要关心哪个 DB 实现提供了数据。另外,我们inverted dependencies这里:ResultReteriver
是 注入(inject) 它的 Database
实例。它不知 Prop 体是哪个 Database
它得到的实现。它不需要。它所关心的只是它是一个有效的。您现在可以轻松实现 MySQL
Database
类(class):class MySqlDatabase<T> implements Database<T> {
create(object: T): Promise<void> {...}
get(id: string): Promise<T> {...}
getAll(): Promise<T[]> {
const db = await mysql.createConnection(options);
const results = await db.execute('SELECT `something` from `table`;');
await db.end();
return results;
}
update(id: string, object: T): Promise<void> {...}
delete(id: string): Promise<void> {...}
}
现在我们已经从您的主要代码库中完全抽象出特定于 MySQL 的实现。说到测试,可以写一个简单的MockDatabase
:export class MockDatabase<T> implements Database<T> {
private objects: T[] = [];
async create(object: T): Promise<void> {
this.objects.push(object);
}
async get(id: string): Promise<T> {
return this.objects.find(o => o.id === id);
}
async getAll(): Promise<T[]> {
return this.objects;
}
update(id: string, object: T): Promise<void> {...}
delete(id: string): Promise<void> {...}
}
说到测试,您现在可以测试您的 ResultRetrieve
使用您的 MockDatabase
而不是依赖 MySQL 库,因此完全模拟它:describe('ResultRetriever', () => {
let retriever: ResultRetriever;
let db: Database;
beforeEach(() => {
db = new MockDatabase();
retriever = new ResultRetriever(db);
});
...
});
如果我有点超出了问题的范围,我很抱歉,但我觉得仅仅回答如何模拟 MySQL 库并不能解决底层的架构问题。
如果您不使用/不想使用 TypeScript,则可以将相同的逻辑应用于 JavaScript。
关于mysql - 用 Jest 模拟 mysql 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63596277/