Pmi*_*its 3 mysql unit-testing node.js jestjs
尝试测试如下所示的代码:
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 ...
}
Run Code Online (Sandbox Code Playgroud)
我需要以一种允许我使用它返回的任何内容来模拟对execute函数的调用的方式来模拟 mysql 连接。
我试过mysql2/promise模拟整个模块,但当然没有用,因为createConnection被模拟的没有返回任何可以调用该execute 函数的东西。我还尝试只模拟我需要的这 3 个函数,而不是模拟整个模块,例如:
jest.mock('mysql2/promise', () => ({
createConnection: jest.fn(() => ({
execute: jest.fn(),
end: jest.fn(),
})),
}));
Run Code Online (Sandbox Code Playgroud)
但这也不起作用。任何建议都非常感谢。
我会以不同的方式处理这个问题。当你觉得你需要模拟整个第三方库进行测试时,你的应用程序中出现了一些问题。
作为一般的最佳实践,您应该始终包装第三方库。查看此讨论以了解初学者。
基本上的想法是定义您自己的接口到所需的功能,然后使用第三方库实现这些接口。在您的其余代码中,您将只针对接口工作,而不是针对第三方实现。
这有几个优点
那么这怎么可能呢?
首先,定义一个接口,因为它在您的代码中最有用。也许,您的数据库接口可能如下所示:
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>;
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以针对这个Database界面开发整个代码库。当您需要从“表”中检索数据时,您可以使用您的Database实现,而不是在整个代码中编写 MySQL 查询。
我将在ResultRetriever这里举一个非常原始的例子,但可以达到目的:
class ResultRetriever {
constructor(private database: Database<Something>) {}
getResults(): Promise<Something[]> {
return this.database.getAll();
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,您的代码不需要关心哪个 DB 实现提供了数据。此外,我们倒立的依赖性在这里:ResultReteriver被注射的Database实例。它不知道Database它得到了哪个具体实现。它不需要。它所关心的只是它是一个有效的。
您现在可以轻松实现 MySQLDatabase类:
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> {...}
}
Run Code Online (Sandbox Code Playgroud)
现在我们已经从您的主要代码库中完全抽象出特定于 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> {...}
}
Run Code Online (Sandbox Code Playgroud)
在测试方面,您现在可以ResultRetrieve使用您的MockDatabase而不是依赖 MySQL 库进行测试,因此完全模拟它:
describe('ResultRetriever', () => {
let retriever: ResultRetriever;
let db: Database;
beforeEach(() => {
db = new MockDatabase();
retriever = new ResultRetriever(db);
});
...
});
Run Code Online (Sandbox Code Playgroud)
如果我有点超出了问题的范围,我很抱歉,但我觉得仅仅回答如何模拟 MySQL 库并不能解决底层的架构问题。
如果您不使用/不想使用 TypeScript,则可以将相同的逻辑应用于 JavaScript。
| 归档时间: |
|
| 查看次数: |
4767 次 |
| 最近记录: |