使用h2在本地跑db单测

2017年10月01日

前言

对DB层的单测来说,如果使用mysql作为数据库,则会有两个问题,第一个问题是,目前公司的测试环境的数据库,无法通过本地直接连接,而如果使用本地mysql进行测试,则测试代码无法在另一个开发人员的机器上正确运行。第二个问题是,即使有公共的测试库,单测也是无法重复运行的,第一次的运行结果可能会影响第二次的运行,其他开发人员对测试库的操作,可能会影响你本次单测的结果。

综上,所以在这里决定使用 h2数据库(H2数据库) 的内存模式在本地进行单测。

Coding

整个项目基于 spring boot ,ORM框架使用 Mybatis.

先将 Mybatis的Mapper文件,以及数据源相关的配置写好:

数据po(省略getter,setter):

      public class UserInfo {
        private long id;
        private String name;
        private String password;
      }

mapper代码:

      @Mapper
      public interface UserDao {

        @Select("select * from user_info where id=#{id}")
        UserInfo findByid(@Param("id") long id);

      }

数据源配置代码:

    @Configuration
    public class BeanConfig {

      private static final Logger LOG = LoggerFactory.getLogger(BeanConfig.class);

      @Bean
      public DataSource dataSource(PoolProperties poolProperties) {
        LOG.info("database properties detail {}", poolProperties);
        return new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
      }

      @Bean
      @ConfigurationProperties("databaseProperties")
      public PoolProperties databaseProperties() {
        return new PoolProperties();
      }
    }

spring boot项目启动类:

    @SpringBootApplication
    public class Application {

      public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
      }

    }

然后在test下面的resources目录下创建配置文件 application.yml(使用yml编写):

注意:这里url中 mem 表示的是使用内存模型,不将数据库中的数据持久化到磁盘关于Url的参数说明

    databaseProperties:
        url: jdbc:h2:mem:test;MODE=MYSQL
        username:
        password:
        driverClassName: org.h2.Driver

    mybatis:
        mapperLocations: com.jaky.test.demo.dao.*

UserDao对应的测试类:

      @SpringBootTest
      @RunWith(SpringRunner.class)
      @Sql(scripts = {"classpath:sql/create_table.sql", "classpath:sql/insert_data.sql"},
      config = @SqlConfig(dataSource = "dataSource"))
      public class UserDaoTest {

          private static final Logger LOG = LoggerFactory.getLogger(UserDaoTest.class);

          @Resource
          private UserDao userDao;

          @Test
          public void find_one_test() {
              UserInfo info = userDao.findByid(1);
              Assert.assertNotNull(info);
              Assert.assertEquals(1, info.getId());
              Assert.assertEquals("jaky.wang", info.getName());
          }
    }

其中在before() 方法中是对数据库进行数据初始化的逻辑,在test的resources中新建sql目录,并创建 create_table.sql,和 insert_data.sql 文件。两个文件的内容分别为:

create_table.sql:

    create table user_info (
    id bigint(20) auto_increment comment '主键id',
    name varchar(20) not null default '' comment '名字',
    password varchar(30) not null default '' comment '密码',
    primary key (id)
    )engine=innodb default charset=utf8;

insert_data.sql:

    insert into user_info(name, password) values('jaky.wang', 'jaky.wang password');

最后执行 UserDaoTest的find_one_test() 方法即可运行,并且无论重复多少次,find_one_test()的结果都不会改变。

h2 兼容性

h2 数据库和mysql数据的一些有一些兼容性问题,例如 双引号 中的内容会被 h2 当成字段名称,其他详细的说明可查看:传送门

项目地址

本文中的代码均可在 这个仓库 的 test-demo 模块中找到。

其他

加上 @SpringBootTest 注解后,spring boot 是如何找到并初始化整个容器的?

SPringRunner在启动时,会加载在spring-boot-test包的META-INFO的spring.factories中的处理类,其中 org.springframework.boot.test.context.SpringBootTestContextCustomizerFactory 类就是处理 @SpringBootTest 注解的类。