什么负责在JUnit / Spring测试期间触发Hibernate的SchemaExport.execute(hbm2ddl.auto)?

时间:2014-07-01 20:29:27

标签: spring-test

在使用SchemaExport.execute的JUnit / Spring测试运行期间,负责触发Hibernate的hbm2ddl.auto(考虑到SpringJUnit4ClassRunner已激活)的Spring事件是什么?

(考虑到所有这些,我可以拥有几个具有相同上下文配置的测试套件,并且可以缓存弹簧上下文......)

我问这个问题是因为我已经设置了一个Spring监听器(用作数据填充器),如下所示:

@Profile({ Profiles.DEFAULT, Profiles.CLOUD, Profiles.TEST, Profiles.DEV })
@Component
public class BootstrapLoaderListener implements ApplicationListener<ContextRefreshedEvent>, ResourceLoaderAware, Ordered {

    private static final Logger log = Logger.getLogger(BootstrapLoaderListener.class);

    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }

    @Override
    @Transactional
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        initApplication();
    }
    ...

我有两个集成测试套件(SpringJUnit4ClassRunner),它们共享相同的上下文配置,因此共享相同的缓存应用程序上下文。

但是我注意到当两个测试套件中的第二个在第一个之后运行时,上面的应用程序监听器不会得到通知。

总结一下:

  • 运行第一个测试套件(使用模式导出创建表,并通知应用程序侦听器)
  • 第二个测试套件运行(只创建表但没有通知应用程序监听器)

1 个答案:

答案 0 :(得分:1)

ContextRefreshedEvent的Javadoc明确指出它是......

  

ApplicationContext初始化或刷新时引发的事件。

因此,只有在BootstrapLoaderListener启动(即初始化或刷新)时才会调用ApplicationContext,这只会发生一次:当Spring TestContext Framework加载测试的上下文时。但是,如果您使用@DirtiesContext,则ApplicationContext可能会多次重新创建。

换句话说,您目睹的关于听众的行为是设计和预期的。

至于为什么你的架构会第二次创建,这仍然是一个谜。通常这不应该发生。例如,如果您使用的是Spring LocalSessionFactoryBeanLocalSessionFactoryBuilder,那么每个工厂只会在初始化或刷新SessionFactory时创建一次Hibernate ApplicationContext

也许您有一些非标准配置导致SessionFactory被多次创建,但我无法根据您提供的信息来判断。

但是,如果您希望在每次测试之前调用设置代码(仅仅因为它不会自动多次调用),则建议不要使用ApplicationListener来设置测试数据库。如果您确实想在测试中使用ApplicationListener,则可以在ContextRefreshedEventApplicationContext方法中为@Before中的@BeforeTransaction个人发起测试

作为替代方案(可能更好的解决方案),您可以通过以下方式之一以编程方式在@Before@BeforeTransaction方法中调用SQL脚本:

  • 其中一个SimpleJdbcTestUtils.executeSqlScript(...)方法(在Spring 2.5 - 3.x上)
  • JdbcTestUtils.executeSqlScript(...)方法之一(在Spring 4.x及更高版本上)
  • ScriptUtils.executeSqlScript(...)方法之一(在Spring 4.0.3及更高版本上)
  • executeSqlScript(...)AbstractTransactionalJUnit4SpringContextTests
  • 中的AbstractTransactionalTestNGSpringContextTests方法
  • 一个ResourceDatabasePopulatorDatabasePopulatorUtils

从尚未发布的Spring 4.1开始,您可以通过@Sql注释以声明方式调用SQL脚本。

祝你好运!

Sam(Spring TestContext Framework的作者)

P.S。您还可以使用上面提到的相同选项实现自定义TestExecutionListener以编程方式调用SQL脚本。