You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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模拟,完全不需要真实数据库连接:

  1. 先安装依赖:
    npm i pg-mem -D
  2. 编写测试用例:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 20:36:06