Vapor单元测试后数据库未清空,二次运行报冲突错误如何解决?
问题根因
- 迁移回滚逻辑失效
所有Migration的revert方法调用的是.update()方法,该方法仅用于修改表结构,不会删除已有表或清空表数据,autoRevert()执行时完全无法清理上一次测试写入的用户数据,第二次测试重复注册同个邮箱时就会返回HTTPStatus.conflict。同时无修改逻辑的空update请求发送到Postgres后,会触发syntax error at end of input语法报错。 - 测试环境数据库端口不匹配
docker-compose-testing.yml中测试服务配置的DATABASE_PORT=5434,但postgres服务默认端口为5432,未做端口修改配置,会导致测试服务数据库连接异常。
修复方案
1. 修正所有迁移的回滚逻辑
将所有Migration的revert方法中的.update()替换为.delete(),执行回滚时直接删除整个表,保证每次测试重建的表都是空表:
修正后的用户迁移回滚代码
struct UserModelMigration_v1_0_0: Migration { func prepare(on database: Database) -> EventLoopFuture<Void> { database.schema(UserModel.schema) .id() .field(UserModel.Key.email, .string, .required) .field(UserModel.Key.password, .string, .required) .unique(on: UserModel.Key.email) .create() } func revert(on database: Database) -> EventLoopFuture<Void> { database .schema(UserModel.schema) .delete() } }
修正后的地址迁移回滚代码
struct AddressModelMigration_v1_0_0: Migration { func prepare(on database: Database) -> EventLoopFuture<Void> { database.schema(AddressModel.schema) .id() .field(AddressModel.Key.streetLineOne, .string, .required) .field(AddressModel.Key.city, .string, .required) .field(AddressModel.Key.userID, .uuid, .required, .references(UserModel.schema, .id, onDelete: .cascade, onUpdate: .cascade)) .unique(on: AddressModel.Key.userID) .create() } func revert(on database: Database) -> EventLoopFuture<Void> { database .schema(AddressModel.schema) .delete() } }
迁移回滚会按照添加顺序逆序执行,先删除Address表再删除User表,符合外键约束要求,不会触发依赖报错。
2. 修正测试环境端口配置
修改docker-compose-testing.yml中测试服务的数据库端口配置,和postgres默认端口对齐:
testingonlinux: environment: - DATABASE_HOST=postgres - DATABASE_PORT=5432
3. 可选:测试执行时自动清理Docker残留
运行测试时添加--volumes参数,测试结束后自动删除postgres的挂载卷,确保每次测试都是完全干净的数据库环境:
docker-compose -f docker-compose-testing.yml down --volumes && docker-compose -f docker-compose-testing.yml up --abort-on-container-exit
内容的提问来源于stack exchange,提问作者Roland Lariotte
相关产品推荐
相关产品推荐

