为什么 @Sql 执行后测试仍提示 relation "foo" does not exist?
数据阿明
结论
问题更可能出在 SQL 脚本与测试数据库的执行时机不一致。@Sql 设置为 BEFORE_TEST_CLASS 时,脚本只会在测试类运行前执行一次;Zonky 嵌入式数据库则配置为 BEFORE_EACH_TEST_METHOD,会在每个测试方法运行前刷新数据库。如果刷新操作重建了数据库,类级脚本创建的表就不会保留到后续测试中,查询时便会出现 relation "foo" does not exist。
让脚本在每个测试方法前执行
将执行阶段改为 BEFORE_TEST_METHOD,并通过 scripts 明确列出脚本:
@Sql(
scripts = [
"/db/migration/V1.0__2022_01_21_00__setup_schema.sql",
"/db/test/V2.0__insert_data.sql"
],
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD
)
这样每个测试方法运行前都会先执行建表脚本,再执行插入数据脚本。此方案要求数据库刷新先于 @Sql 执行。如果逐方法执行后仍报错,请检查数据库配置和测试监听器的实际执行顺序。
检查资源路径
@Sql 中以 / 开头的路径从 classpath 根目录解析。确认两个文件在测试运行时位于对应位置,例如 src/test/resources/db/migration/... 和 src/test/resources/db/test/...。项目目录显示为 test/db/test/,不能据此确认运行时路径就是 /db/test/...。
@Sql 会将指定文件作为 SQL 脚本执行,不会按 Flyway 的迁移流程处理,也不会替代 Flyway 的版本管理。如果希望由 Flyway 负责建表和迁移,请检查 spring.flyway.locations 是否包含迁移文件所在的 classpath 目录,并查看 Flyway 日志,确认它实际发现和执行了哪些脚本。
仍报错时的排查顺序
- 确认建表脚本包含创建
foo表的语句,且执行时没有报错。 - 确认
@Sql脚本路径与测试运行时 classpath 一致。 - 确认建表脚本先于插入脚本执行,并且插入脚本使用的 schema 与测试查询一致。
- 检查数据库在每个测试方法的哪个阶段刷新,避免刷新操作清除
@Sql创建的表。
备注:内容仅供参考。
