使用Junit4从测试场景的准备优化测试脚本的执行效率
Junit4提供了两种测试场景的准备与恢复方式,@BeforeClass,@AfterClass和@Before,@After。一般来说测试场景的准备与恢复就是在运行测试方法前准备测试数据,运行完成后再回收这些测试数据以使测试场景恢复到测试前的状态。下面先看看分别使用这两种方式的区别,请看下面的测试脚本框架:
第一种方式(@BeforeClass和@AfterClass):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class SomeClassTest { @BeforeClass public static void beforeClass(){ //在这里准备场景数据(1) } @AfterClass public static void afterClass(){ //在这里恢复场景数据(2) } @Test public void testSomething1(){ //第一个测试方法,在这里编写要测试的东西(3) } @Test public void testSomething2(){ //第二个测试方法(4) } }
请看其中的序号,使用这种方式准备数据的时候脚本的执行顺序是这样的:(1)→(3)→(4)→(2),使用这种方式来准备数据和恢复数据的时候是一次性的,即在该测试类的所有测试方法执行前加载一次数据,在所有测试方法执行后恢复一次数据。
第二种方式(@Before和@After):
public class SomeClassTest { @Before public void before(){ //在这里准备场景数据(1) } @After public void after(){ //在这里恢复场景数据(2) } @Test public void testSomething1(){ //第一个测试方法,在这里编写要测试的东西(3) } @Test public void testSomething2(){ //第二个测试方法(4) } }
使用第二种方式准备数据的时候脚本的执行顺序是这样的:(1)→(3)→(2)→(1)→(4)→(2),使用这种方式来准备数据和恢复数据的时候,会在该测试类的每个测试方法执行前加载一次数据,然后在每个测试方法执行后恢复一次数据。总而言之,前一种方式是类级别的,而后一种是方法级别的。
很显然,第一种场景准备与恢复方式的执行效率肯定高于第二种方式的执行效率,并且一个测试类里的测试方法越多这种差别越大。在测试脚本的执行中,我为什么会想到数据加载的执行效率呢?因为在运行测试脚本的过程中我发现,很多时候采用第一种方式一次性准备数据,一个测试方法的执行时间大概只有几毫秒;而使用第二种方式的执行时间通常都是在秒级别的,因为每个方法执行前后都要有一次数据准备与恢复操作,不仅耗时(单从每个测试方法的执行效率来看,差别是上千倍的)而且频繁的数据库操作也大大增加了出错的几率。
于是在测试脚本的编写过程中,数据的准备与恢复我都尽量采用第一种方式,but古语有云:有所得,必有所失;有所失,必有所得。就这两种方式而言,第一种虽然执行效率高,但是不安全,因为它的数据是一次性准备的,那么在执行前一个测试方法的时候可能对这些数据造成了一些更改,而这些更改对于后续的测试方法来说是不期望的,也就是对后面的测试方法造成了场景数据的污染,使得后续的测试方法执行失败。而相对于第一种方式来说,第二种方式就安全多了,因为它可以保证每个测试方法执行的时候用的都是我们所准备的场景数据。
那么,我们该怎么解决这个矛盾呢?原则还是不变,尽量使用类级别的数据准备与恢复方式。请注意,我这里说的是类级别,而没有说是第一种方式,虽然它们是等价的。那么这个类级别是针对什么而言呢?显然,说它是类级别,因为它有@BeforeClass和@AfterClass标签,而这个标签是JUnit的,也就是说只有JUnit在运行该类的时候才会认为它是类级别的,从而只执行一次数据准备与恢复。而这个标签对于我们人而言是无效的,所以我的解决方法就出来了,其实很简单,那就是在有对场景数据进行写操作的测试方法最后手动去调用一次@AfterClass和@BeforeClass所标注的方法。请注意这里的顺序是先调用@AfterClass标准的方法删除被污染的场景数据,再调用@BeforeClass所标注的方法重新加载一遍场景数据。我把这种方式命名为“谁污染,谁治理”。^_^
根据我的实际应用效果来看,这种方法还是很有效的,特别是当一个测试类中有很多测试方法,而这些测试方法所用到的场景数据基本上都一样且会造成场景数据污染的测试方法数所占比例不大的时候尤其好使,大家可以试试。
讲到最后,不知道大家有没有注意到一个细节,用@BeforeClass、@AfterClass和@Before、@After所标注的方法有一个小小的差别。那就是Junit4规定用@BeforeClass、@AfterClass所标注的方法必须是静态的,而用@Before、@After所标注的方法不能是静态的。