Spring Hibernate H2 Junit 测试 - 如何在启动时加载模式

Posted

技术标签:

【中文标题】Spring Hibernate H2 Junit 测试 - 如何在启动时加载模式【英文标题】:Spring Hibernate H2 Junit testing - how to load schema on start 【发布时间】:2016-07-25 12:59:56 【问题描述】:

我正在尝试为我的应用程序开发测试(我很晚才发现这些测试......)但我被卡住了,基本配置也被卡住了。我用谷歌搜索了很多例子,但没有一个让我满意,坦率地说让我有点困惑。

我想要实现的是在测试开始时加载 import.sql(这是现有 mysql 模式的转储文件)并将其加载到 H2 数据库中。

这里是休眠配置文件:

@Configuration
@EnableTransactionManagement
@ComponentScan( "kamienica.feature" )
public class HibernateTestConfiguration 

    @Autowired
    ApplicationContext applicationContext;

    @Bean
    public LocalSessionFactoryBean sessionFactory() 
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[]  "kamienica" );
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    

    @Bean(name = "dataSource")
    public DataSource dataSource() 
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;"
                + "INIT=CREATE SCHEMA IF NOT EXISTS kamienica;DB_CLOSE_ON_EXIT=FALSE");
        dataSource.setUsername("sa");
        dataSource.setPassword("");

        return dataSource;
    

    private Properties hibernateProperties() 
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        properties.put("hibernate.hbm2ddl.auto", "update");
// this is where I tried to load script the first time:
// properties.put("hibernate.hbm2ddl.import_files", "kamienica.sql");
        return properties;
    

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) 
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(s);
        return txManager;
    

每次我开始测试时都会收到一条消息:

org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata 信息: HHH000262:找不到表:公寓

我在尝试检索任何内容时得到空/空值

我尝试在休眠配置(通过休眠属性)以及计划扩展的所有测试类的超类中加载 sql 文件:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes =  HibernateTestConfiguration.class )
public class BaseTest 

    private EmbeddedDatabase db;

    @Autowired
    private SessionFactory sessionFactory;

    //second attempt to load sql file
    @Before
    public void setUp() throws Exception 
        db = new EmbeddedDatabaseBuilder().addScript("import.sql").build();
    

    @After
    public void tearDown() throws Exception 
        SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
        SessionFactoryUtils.closeSession(sessionHolder.getSession());
    


如何加载 sql 文件并准备 H2 数据库以执行测试?

【问题讨论】:

我不知道这对你来说是不是有点过头了,但是在 CI/CD 的情况下,你会使用 Flyway 之类的东西来为你管理你的数据库模式,并且非常乐意构建它用于测试数据库。 【参考方案1】:

我希望这个 Spring Boot 方法对您有所帮助。首先在项目根目录下的 src/test 目录下创建一个resources目录(springboot的类路径)。 在此目录中,您将开始放置名为 data.sql 的夹具 SQL 数据文件。 然后,在同一级别创建一个 application.properties 文件(同一目录见截图)。该文件应如下所示填充:

spring.datasource.url = jdbc:h2:~/test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
#spring.datasource.url: jdbc:mysql://localhost:3306/yourDB
#spring.datasource.username = root
#spring.datasource.password =

# Hibernate
hibernate.show_sql: true
#hibernate.dialect: org.hibernate.dialect.MySQL5Dialec
spring.jpa.hibernate.ddl-auto=none

截图:

现在你的测试方法。

@RunWith(SpringJUnit4ClassRunner.class) 
....
            @Autowired
            private DataSource ds; //your application.properties
            @Autowired
            private WebApplicationContext context;
            private static boolean loadDataFixtures = true;
            private MockMvc mockMvc;
        ....

         @Before
         public void setupMockMvc() 
         mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
        




        @Before
            public void loadDataFixtures() 
                 if (loadDataFixtures) 
                    ResourceDatabasePopulator populator = new ResourceDatabasePopulator(context.getResource("classpath:/data.sql"));
                    DatabasePopulatorUtils.execute(populator, ds);
                    loadDataFixtures = false;
                
            

@Test
public void yourmethod() 
    assertEquals(3, repository.count()); //example

【讨论】:

【参考方案2】:

没有任何输出或完整的堆栈跟踪,我唯一可以建议您的是:

    您没有显示任何@Test 方法。你是怎么得到这个错误的? 您的文件import.sqlsrc/test/resources 文件夹中吗? (注意测试路径) 您的 sql 脚本格式是否正确?您是否尝试过在导出后运行?您能否发布创建 apartment 表的 sql 脚本部分?

如果一切都是真的,也许问题不在于加载sql,而在于它是如何使用的,或者脚本的内容,或者表的名称等等......

【讨论】:

【参考方案3】:

经过长时间的“调查”,我得出的结论是问题隐藏在 DBUnit、TestNG 设置中的某个地方。

我决定保持简单并切换到 JUnit 测试。

如果其他人可能有类似的问题,这里是适合我的配置文件:

@Configuration
@EnableTransactionManagement
@ComponentScan( "kamienica.feature" )
public class JUnitConfig 

    @Bean
    public LocalSessionFactoryBean sessionFactory() 
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[]  "kamienica" );
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    

    @Bean(name = "dataSource")
    public DataSource dataSource() 
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:mem:kamienica;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");

        dataSource.setUsername("sa");
        dataSource.setPassword("");
        return dataSource;
    

    private Properties hibernateProperties() 
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        properties.put("hibernate.hbm2ddl.auto", "create");
        return properties;
    

    @Bean
    public HibernateTransactionManager transactionManager(SessionFactory s) 
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(s);
        return txManager;
    


现在只需要在资源文件夹中插入 import.sql 文件。 我还发现每条insert语句不管多长都必须在一行,否则加载不出来。

最后是一个简单的测试类:

@ContextConfiguration(classes =  JUnitConfig.class )
@RunWith(SpringJUnit4ClassRunner.class)
public class ApartmentServiceTest extends AbstractServiceTest

    @Autowired
    ApartmentService service;


    @Test
    public void getList() 
        List<Apartment> list = service.getList();
        System.out.println(list.toString());
        assertEquals(5, list.size());
    

【讨论】:

以上是关于Spring Hibernate H2 Junit 测试 - 如何在启动时加载模式的主要内容,如果未能解决你的问题,请参考以下文章

Spring Hibernate H2 Junit 测试 - 如何在启动时加载模式

防止在 JUnit 中执行 jpa @Query

Spring4 JUnit 测试:将 SQL 加载到 H2 数据库

使用 h2 进行 Spring Junit 测试 - 找不到表

JUnit4、Spring、Hibernate 测试上下文设置

使用 H2 DB 进行 Spring/Hibernate 集成测试