如何使用pg-mem的clone函数解决测试时schema变更引发的备份恢复报错
解决方案
backup.restore()仅支持备份后schema未发生修改的场景,只要测试中出现创建/删除表、修改字段结构等schema变更操作,就会触发对应报错,官方推荐使用clone()方法处理这类场景。
clone()方法用法
clone()是pg-mem核心实例(即newDb()返回的对象)的原生方法,作用是深拷贝当前实例的完整状态(包含所有schema定义、预置数据),拷贝生成的新实例完全独立,和原实例互不影响,性能远高于每次调用newDb()重新初始化。
最终实现代码
import { newDb } from 'pg-mem'; import {createTables} from './database'; // 初始化基础模板实例,仅执行一次 let baseDbTemplate; let templateInitialized = false; export const getTestDatabase = async () => { // 首次调用初始化基础模板,完成表创建等公共初始化逻辑 if (!templateInitialized) { templateInitialized = true; baseDbTemplate = newDb(); // 先在模板实例上完成schema初始化 const templateDb = await baseDbTemplate.adapters.createPgPromise(); templateDb.connect(); await createTables(templateDb); // 初始化完成后关闭模板的适配器连接,避免占用 templateDb.$pool.end(); } // 每次测试克隆独立实例,完全隔离 const testDbInstance = baseDbTemplate.clone(); // 基于克隆实例生成pg-promise适配器 const database = await testDbInstance.adapters.createPgPromise(); database.connect(); return database; };
方案优势
- 彻底避免重复数据库连接警告:仅初始化一次基础模板,后续所有测试用的都是克隆实例生成的独立适配器,不会触发pg-promise的重复对象校验
- 支持任意schema修改场景:每个测试的数据库实例完全独立,修改schema不会影响其他测试,也不会触发备份还原的schema校验错误
- 性能更优:仅执行一次公共初始化逻辑,克隆操作的开销远低于每次重新建表初始化
补充:如果确认无需保留测试间的schema变更,也可以在每次测试结束后主动回滚所有DDL操作,但上述clone方案适配性更强,维护成本更低。
内容的提问来源于stack exchange,提问作者mtmacdonald
相关产品推荐
相关产品推荐

