@SpringBootTest 和 @Sql:脚本执行顺序和上下文初始化

Posted

技术标签:

【中文标题】@SpringBootTest 和 @Sql:脚本执行顺序和上下文初始化【英文标题】:@SpringBootTest with @Sql: order of script execution and context initialization 【发布时间】:2017-10-10 09:35:49 【问题描述】:

我有在内存数据库上执行的集成测试。每个测试的签名或多或少看起来像这样:

@RunWith(SpringRunner.class)
@SpringBootTest
@Sql("/clean-data-in-all-tables.sql")
public class SomeTest  
    @Test
    public void shouldDoSomehting() 

在测试上下文初始化期间,数据库模式由 Hibernate 重新创建:

spring:
  jpa:
    hibernate:
      ddl-auto: create-drop

我希望在初始化上下文和生成数据库模式之后执行 sql 脚本。但是在某些情况下,clean-data-in-all-tables.sql 在架构生成之前执行,它会失败,因为它需要尚未创建的表。

我已经按照我解释的方式编写了 500 多个测试,并且在我添加了几个类似的测试之前,它们都运行良好。

当我通过 Gradle 或 IntelliJ 一起执行测试时,测试失败。 请注意,失败的测试不是最近添加的测试。这是与我添加的完全无关的旧测试。同样奇怪的是,失败的测试如果我通过 IntelliJ 一个一个运行效果很好。

它看起来像 spring-boot 的错误,但我仍然试图找到解决它的方法。与此同时,我尝试了很多方法来解决这个问题,但没有一个是有帮助的。

请分享您对我的代码有什么帮助以及可能有什么问题的想法。

更新: 找到解决方法:将spring.jpa.hibernate.ddl-autocreate-drop 更改为create 即可解决问题。

但问题仍然悬而未决这种奇怪行为的原因是什么?

【问题讨论】:

您是否添加了任何新配置? SpringBootTest 正在寻找从测试包到项目根目录的配置。 不,我没有引入任何新配置,也没有更改现有配置。 【参考方案1】:

一种可能的解决方案(我不确定您是否愿意使用 DBUnit)是:

1) 创建抽象存储库集成测试:

@TestExecutionListeners(DbUnitTestExecutionListener.class)
@SpringApplicationConfiguration(classes = Application.class)
@DirtiesContext
public abstract class AbstractRepositoryIT extends AbstractTransactionalJUnit4SpringContextTests 

2) 创建“真正的”集成测试:

@DatabaseSetup(SomeEntityRepositoryIT.DATASET)
@DatabaseTearDown(type = DatabaseOperation.DELETE_ALL, value = "dataset.xml)
public class SomeEntityRepositoryIT extends AbstractRepositoryIT 
...

在文件 dataset.xml 中,您可以为测试等设置初始状态... More can be found here

【讨论】:

谢谢。不幸的是我不能使用 DbUnit。更重要的是我现有的测试配置出了什么问题。 是的,我明白这一点。但还有一个问题 - sql 文件被称为“clean-data-in-all-tables.sql” - 它是否仅用于删除(回滚)在测试期间插入数据库的所有数据?也许您最终可以找到一些不需要的解决方案?比如在你的测试类上使用@Transactional? 我们曾经使用@DirtiesContext 来清理数据库,但是它会增加2-3 倍的测试运行时间。 还有一个问题——你在 gradle 中有一些自定义任务来运行测试吗?您是否“玩”过诸如 maxParallelForks 和 forkFor 之类的属性,然后您的测试并行运行,这就是为什么当您运行所有这些属性时有些下降,而当您一个接一个运行时不会下降的原因? 不,gradle 任务没有任何变化

以上是关于@SpringBootTest 和 @Sql:脚本执行顺序和上下文初始化的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2 - H2 数据库 - @SpringBootTest - org.h2.jdbc.JdbcSQLException 失败:表已存在

可以为每个 SpringbootTest 注释加载特定的 data.sql

@DataJpaTest 不会读取 spring.jpa.* 属性,而 @SpringBootTest 会

调试器、@SpringBootTest 和 Gradle

SpringBootTest - 如何在测试级别断言上下文不加载和更改属性?

使用 SpringBootTest 和 Autowired 注解时 LogCaptor 无法捕获