如何使用Jasmine或第三方库在Node.js中Mock postgresql(pg)完成测试
两种常用的测试方案
你提到的两种思路都可以实现测试,根据你的测试目标选择即可:
方案1:Stub PG.Client 的query方法(单元测试首选)
这种方案不需要关心SQL本身的正确性,只验证方法内的业务逻辑是否符合预期,实现简单,执行速度快。以Jest为例,其他测试框架(Vitest、Sinon等)逻辑一致:
首先Mock整个pg模块的Client构造函数,替换为返回带模拟方法的实例:
// 测试文件顶部mock pg模块 jest.mock('pg', () => { const mockClient = { connect: jest.fn(), query: jest.fn(), }; return { Client: jest.fn(() => mockClient) }; });
编写测试用例:
import { Client } from 'pg'; import { getActiveUsersLast7DaysForProject } from './你的代码文件路径'; describe('getActiveUsersLast7DaysForProject', () => { const mockClient = new Client() as jest.Mocked<Client>; afterEach(() => jest.clearAllMocks()); it('查询成功时返回正确的用户ID数组', async () => { // 模拟query返回结果 mockClient.query.mockResolvedValue({ rows: [{ user_id: 'u1' }, { user_id: 'u2' }, { user_id: 'u3' }] }); const res = await getActiveUsersLast7DaysForProject('test-pid'); expect(mockClient.connect).toHaveBeenCalledTimes(1); expect(mockClient.query).toHaveBeenCalledWith(expect.stringContaining('SELECT user_id FROM my_db.users_active')); expect(res).toEqual(['u1', 'u2', 'u3']); }); it('查询失败时返回空数组并打印错误', async () => { const testError = new Error('查询失败'); mockClient.query.mockRejectedValue(testError); const consoleSpy = jest.spyOn(console, 'error').mockImplementation(); const res = await getActiveUsersLast7DaysForProject('test-pid'); expect(consoleSpy).toHaveBeenCalledWith(testError.stack); expect(res).toEqual([]); consoleSpy.mockRestore(); }); });
方案2:使用pg-mem模拟真实数据库(集成测试首选)
如果你需要验证SQL语法、查询条件、分组逻辑的正确性,可以用pg-mem实现本地内存级的PostgreSQL模拟,完全不需要真实数据库连接:
- 先安装依赖:
npm i pg-mem -D - 编写测试用例:
import { newDb } from 'pg-mem'; import { getActiveUsersLast7DaysForProject } from './你的代码文件路径'; // mock pg模块替换为pg-mem的兼容实例 jest.mock('pg', () => { // 初始化内存数据库 const db = newDb(); // 提前创建测试需要的表、插入测试数据,和生产表结构对齐 db.public.none(` CREATE TABLE users_active ( user_id VARCHAR(64), project_id VARCHAR(64) ); INSERT INTO users_active(user_id, project_id) VALUES ('u1', '12345'), ('u2', '12345'), ('u3', '67890'), ('u1', '12345'); `); // 返回和pg兼容的Client构造函数 return { Client: db.adapters.createPg().Client }; }); describe('getActiveUsersLast7DaysForProject 集成测试', () => { it('正确按项目ID过滤并去重返回用户ID', async () => { const res = await getActiveUsersLast7DaysForProject('12345'); // 验证GROUP BY去重、project_id过滤逻辑生效 expect(res).toEqual(['u1', 'u2']); }); });
额外优化建议
你当前的代码有两个可优化点:
- 硬编码了SQL里的
project_id='12345',没有使用入参projectId,会导致逻辑错误 - 没有使用参数化查询,存在SQL注入风险
建议修改query部分的代码:
await client.query( 'SELECT user_id FROM my_db.users_active ua WHERE ua.project_id = $1 GROUP BY user_id', [projectId] )
内容的提问来源于stack exchange,提问作者ignite-me
相关产品推荐
相关产品推荐

