H2单元测试与业务数据隔离之内嵌模式

Posted boonya

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H2单元测试与业务数据隔离之内嵌模式相关的知识,希望对你有一定的参考价值。

目录

H2支持数据库模型

URL编写构造器

H2Helper用于建表、插入和查询操作

单元测试示例


在日常编码过程中,单元测试作为代码的质量校验最重要的手段之一,必须做好数据隔离和代码充分的测试。数据侵入会造成测试困扰。为规范日常单元测试,通常使用H2内存数据库来实现单元测试数据库数据持久化校验。h2分为三种使用场景:内嵌模式、服务器模式和混合模式。本篇讲述的是内嵌模式。

H2支持数据库模型

h2支持的数据库模型如下

 public static enum ModeEnum 
        REGULAR,
        DB2,
        Derby,
        MSSQLServer,
        HSQLDB,
        mysql,
        Oracle,
        PostgreSQL,
        Ignite;

        private ModeEnum() 
        
    

URL编写构造器

下面是本地化的文件和内存数据库实现的Builder

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class H2URLBuilder 

    final String start="jdbc:h2:";
    Mode.ModeEnum mode;
    String scriptPath;
    boolean isInit;
    boolean isDbCloseDelay;

    public String getURL()
        StringBuilder sb = new StringBuilder();
        sb.append(start).append(isInit?"~/test":"mem:test");
        if(null == mode)
            throw  new UnsupportedOperationException("mode can not be null");
        
        sb.append(";MODE=").append(mode);
        if(isInit)
            if(StringUtils.isNullOrEmpty(scriptPath))
                throw  new UnsupportedOperationException("scriptPath is null you need set " +
                        " like ./src/test/resources/createTable.sql");
            
            sb.append(";INIT=runscript from '").append(scriptPath).append("'");
        
        if(isDbCloseDelay)
            sb.append(";DB_CLOSE_DELAY=-1");
        
        return sb.toString();
    

H2Helper用于建表、插入和查询操作

@Slf4j
public class H2Helper 

    /**
     * getJdbcTemplate
     * @param dataSource
     * @return
     */
    public static JdbcTemplate getJdbcTemplate(DataSource dataSource)
        Assert.notNull(dataSource,"dataSource is null");
        return new JdbcTemplate(dataSource);
    

    /**
     * getJdbcTemplate
     * @param builder
     * @return
     */
    public static JdbcTemplate getJdbcTemplate(H2URLBuilder builder)
        DataSource dataSource = H2Helper.getDataSource(builder);
        Assert.notNull(dataSource,"dataSource is null");
        return new JdbcTemplate(dataSource);
    

    /**
     * getDataSource
     * @return
     */
    public static DataSource getDataSource(H2URLBuilder builder)
        JdbcDataSource ds = new JdbcDataSource();
        String url = builder.getURL();
        log.debug("URL--->",url);
        ds.setURL(url);
        ds.setUser("sa");
        ds.setPassword("");
        return ds;
    

    /**
     * createTable
     * @param jdbcTemplate
     * @param sql
     */
    public static void createOrDropTable(JdbcTemplate jdbcTemplate,String sql)
        try (Connection connection = jdbcTemplate.getDataSource().getConnection())
            TransactionSynchronizationManager.initSynchronization();
            connection.setAutoCommit(false);
            jdbcTemplate.execute(sql);
            connection.commit();
         catch (SQLException e) 
            e.printStackTrace();
        finally 
            TransactionSynchronizationManager.clearSynchronization();
        
    

    /**
     * save
     * @param jdbcTemplate
     * @param sql
     * @param args
     */
    public static void save(JdbcTemplate jdbcTemplate,String sql,Object[] args)
        try (Connection connection = jdbcTemplate.getDataSource().getConnection())
            TransactionSynchronizationManager.initSynchronization();
            connection.setAutoCommit(false);
            jdbcTemplate.update(sql,args);
            connection.commit();
         catch (SQLException e) 
            e.printStackTrace();
        finally 
            TransactionSynchronizationManager.clearSynchronization();
        
    

    /**
     * query
     * @param jdbcTemplate
     * @param sql
     * @param args
     * @return
     */
    public static List<Map<String,Object>> select(JdbcTemplate jdbcTemplate,String sql,Object[] args)
        List<Map<String,Object>> queryForList =jdbcTemplate.queryForList(sql,args);
        Assert.notNull(queryForList,"queryForList is null");
        return queryForList;
    

单元测试示例

此处测试脚本文件和内存建库操作

@Slf4j
@SpringBootTest
public class H2HelperTest 

    String insert = "insert into `user`(id,name,mobile) values(?,?,?) ";

    String select = "select * from `user`";

    Object [] args = new Object[]"id_test","name_test","mobile_test";

    @Test
    public void initMode()
        H2URLBuilder builder = H2URLBuilder.builder()
                .isInit(true)
                .mode(Mode.ModeEnum.MySQL)
                .scriptPath("./src/test/resources/createTable.sql")
                .build();
        DataSource dataSource =H2Helper.getDataSource(builder);
        Assert.notNull(dataSource,"dataSource is null");

        JdbcTemplate jdbcTemplate = H2Helper.getJdbcTemplate(builder);
        // save
        H2Helper.save(jdbcTemplate,insert,args);
        // query
        H2Helper.select(jdbcTemplate,select,null);
    

    @Test
    public void memMode()
        H2URLBuilder builder = H2URLBuilder.builder()
                .isInit(false)
                .mode(Mode.ModeEnum.MySQL)
                .build();
        DataSource dataSource =H2Helper.getDataSource(builder);
        Assert.notNull(dataSource,"dataSource is null");

        JdbcTemplate jdbcTemplate = H2Helper.getJdbcTemplate(builder);
        String createTable = "CREATE TABLE `user`  (\\n" +
                " `id` char(32)  NOT NULL,\\n" +
                " `name` varchar(255)  NOT NULL,\\n" +
                " `mobile` varchar(64) DEFAULT NULL\\n" +
                ")";
        // createTable
        H2Helper.createOrDropTable(jdbcTemplate,"DROP TABLE IF EXISTS `user`");
        H2Helper.createOrDropTable(jdbcTemplate,createTable);
        // save
        H2Helper.save(jdbcTemplate,insert,args);
        // query
        H2Helper.select(jdbcTemplate,select,null);
    

测试结果:

参考文章:运行模式 · leaning-h2

 项目地址:daily-code-cache: Spring cache的相关使用。

以上是关于H2单元测试与业务数据隔离之内嵌模式的主要内容,如果未能解决你的问题,请参考以下文章

内存数据库中的 H2:使用 JDBC 设置时区? Java 单元测试

在单元测试时支持 H2 数据库中的 DB2 功能

带有 h2 的 Spring Boot 单元测试失败的模式

连接关闭后 H2 模式消失

H2 - Postgres 模式支持网络数据类型

如何使用 H2 内存数据库编写单元测试