问题的现象描述:项目都使用 spring 作为 ioc 容器,unitils + easymock + dbunit 作为单元测试套餐, 在一个 jar 包下有多个单元测试用例。
- 分别运行测试类下的各个测试函数,全部通过
- 分别运行各个测试类,全部通过
- 通过 mvn test 或在 idea 中右键某个test目录 -> Run tests in xxx, 失败了!
这个问题像幽灵一样,放在一起才出现,想要单独运行或debug去找到原因,却无影无踪。
通过运行日志分析,能找到一些现象。
1. 原本应该运行的代码没有运行到:故意在必经的代码之处通过日志打桩,却不输出日志。
2. 出现了不可能的数据:比如计算得到的时间与输入的相关很远。
3. 数据混乱:取出来的数据对象却是其它测试用例中才会有的。
那么可能出问题的地方有:
1. 某些代码使用了 cache 机制,导致测试时数据只加载一次就不再变更,不能同步 dataset 中的数据。为解决这个问题,在使用 cache 的地方增加开关,在测试时禁用 cache. 经过测试发现,果然影响到了一部分测试结果。
2. mock 的对象被重用了。怀疑这点是有道理的,数据乱串是现象之一。为了解决这个问题,在每个单元测试类的开始使用了重置 mock 的设置,代码如下:
@Before
public void setup(){
EasyMockUnitils.reset();
}
还是没有解决问题。
3. 经过代码分析,测试相关的三大模块中:easymock, spring 都对应的 reset 方法,上面只试了 easymock 的 reset. 如果在每次测试之前都 reset 会怎么样呢?先试试看。在每个测试类中增加下面代码:
@Before
public void setup(){
EasyMockUnitils.reset();
SpringUnitils.invalidateApplicationContext();
}
果然解决了问题!
回过头来分析,原来是 unitils 为了加快单元测试的速度,创建的 spring 容器会重用,几个测试运行下来,容器就被各种 mock 弄乱了,因此在测试之前需要重置。为了提高效率,并不需要在每次运行测试函数时都需要重置函数,只要将它放到测试类的开始即可。代码如下:
@BeforeClass
public void sartup(){
SpringUnitils.invalidateApplicationContext();
}