单测中隔离每个case对DB数据操作
在公司项目中对单测框架做升级的时候,引入了h2数据库,同时希望每个case在访问h2做读写操作之后,不会影响下一个case对h2的数据访问。
1、最先想到的肯定是dbunit和unitils,但经过调研,发现和现有单测框架存在测试入口不一致、构造数据过程繁琐、xml导入的方式或者xsl的方式相比于SQL脚本来说更加麻烦等问题,所以就否了。
2、其次想到的是采用事务管理,spring的testcontext框架中提供了AbstractTransactionalJUnit4SpringContextTests来支持case的事务。每个case之前行都灌入数据,case执行完再通过事务roll back。但是由于系统存在多达30套的datasource,而且并非是由JTA管理。而spring的AbstractTransactionalJUnit4SpringContextTests只能支持单datasource。其源码如下。因而该方案也被否了。
/** * Set the DataSource, typically provided via Dependency Injection. */ @Autowired public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); }
3、第三个想到的是采用spring单测框架中所提供的@DirtiesContext注解,让每个case启动前都去重新加载一遍spring上下文,这样的话,等于每次都把h2数据库给清空了,似乎这样就可以完美地解决问题,但是根据了解,DirtiesContext注解很吃内存,如果case数量太多,会严重影响执行时间,甚至让工程无法install成功,直接导致CI任务执行失败。所以这个方案也被否了。
4、最后采用的折衷方案是,让每个case在执行前执行建库建表语句,再写所需要的DML语句(注解化),case执行完再把所有表删除。其中的建表删表操作都是由框架负责,对使用者透明。这个方案和系统目前使用的单测框架能够很好结合。
所以得出的一个小经验是,没有最好的技术,只有最合适的技术。