如何结合Sequelize增量迁移与测试?初始用sync初始化数据库
增量迁移与测试环境的适配方案
针对你从sequelize.sync()切换到增量迁移,同时要兼顾测试验证的需求,下面是具体的落地步骤:
1. 补全迁移的初始基准
因为之前用sync()直接生成数据库,没有迁移记录,首先要把现有数据库结构转化为第一个迁移脚本,作为后续增量变更的基础:
- 先初始化sequelize-cli的迁移目录:
npx sequelize-cli init - 生成初始迁移文件:
npx sequelize-cli migration:generate --name init-database - 在这个迁移文件的
up方法里,手动编写创建所有现有表的代码(可以对照当前数据库的表结构来写),保证执行这个迁移后得到的数据库和sync()生成的完全一致。这一步是让迁移系统有一个明确的起始状态。
2. 替换测试环境的数据库初始化逻辑
把原来beforeEach里的sync({ force: true })改成先清空数据库,再执行所有迁移脚本,这样测试环境的数据库是通过迁移构建的,和生产环境的变更流程完全对齐:
beforeEach(async () => { // 清空所有表,替代force:true的全量重建 await sequelizeConn.drop(); // 执行所有迁移,从初始到最新的增量变更 await sequelizeConn.getQueryInterface().runMigrations(); });
也可以在测试前用sequelize-cli命令批量执行:
npx sequelize-cli db:migrate:undo:all && npx sequelize-cli db:migrate
如果是在测试代码里集成,直接调用runMigrations更简洁。
3. 编写增量迁移并验证正确性
比如你要给Person表加petName字段,正常写迁移脚本:
'use strict'; module.exports = { async up(queryInterface, DataTypes) { await queryInterface.addColumn('Person', 'petName', { type: DataTypes.STRING, allowNull: true }); }, async down(queryInterface) { await queryInterface.removeColumn('Person', 'petName'); } };
然后在测试里验证迁移效果:
验证正向迁移
test('迁移后Person表新增petName字段', async () => { const tableInfo = await sequelizeConn.getQueryInterface().describeTable('Person'); // 验证字段存在 expect(tableInfo.petName).toBeDefined(); // 验证字段类型符合预期 expect(tableInfo.petName.type).toBe('VARCHAR(255)'); // 根据数据库类型调整,比如MySQL是VARCHAR,PostgreSQL是TEXT });
验证回滚迁移
test('回滚迁移后Person表移除petName字段', async () => { // 执行最后一次迁移的回滚 await sequelizeConn.getQueryInterface().undoLastMigration(); const tableInfo = await sequelizeConn.getQueryInterface().describeTable('Person'); expect(tableInfo.petName).toBeUndefined(); });
4. 日常开发与测试的一致性规范
- 开发环境:不再用
sync({ force: true }),而是用npx sequelize-cli db:migrate来更新数据库,避免手动修改表结构导致和迁移脚本不一致 - 测试环境:每次测试前都通过迁移构建数据库,确保测试用例跑的是和生产完全一致的数据库结构
关键提醒
- 初始迁移脚本必须和当前生产环境的数据库结构完全匹配,否则后续增量迁移会出现结构不一致的问题
- 每个迁移的
up和down方法都要保证逻辑正确,确保正向执行和回滚都能正常工作 - 测试不仅要验证字段存在,还要覆盖字段的属性(是否允许为空、默认值、索引等),避免迁移脚本的细节错误
内容的提问来源于stack exchange,提问作者Mormen
相关产品推荐
相关产品推荐

