前几天看UIC-TEST代码时,顺便也研究了下SpringTest,遇到了不少问题,在这里贴出来,以供后人查看,提高他们的学习效率
SpringTest并不是一个完整的测试框架,它只是为测试提供一些必要的服务,其基石还是JUnit!那么它提供的是什么服务呢?下面我们先来研究一下这个问题
众所周知,我们的开发人员使用spring的依赖注入解决软件构件之间的耦合问题,那我们的测试代码是否也会存在耦合问题呢?我们是针对接口进行测试,但是在执行一个测试类的测试方法之前,我们需要为这个测试方法准备测试场景,不可避免的是要生成一个待测接口的实现类的实例,如下图:
这样做的不好之处在于,如果开发人员更换了接口的实现类,那么我们的测试代码也要做相应的修改以适应新的实现类。如何在不修改代码的情况下就能使我们的测试代码快速切入到新的实现类呢?spring-test凭借spring的原生特性给我们提供了这种便捷.下面我们根据一个简单的例子来展示spring-test是如何工作的,最关键的是要理解spring在什么时候为我们的测试注入接口的实现类对象,这也是本文主要的分享点!请看下面代码:
上面那个问题,往往成为菜鸟的一个障碍,当时我在研究类似代码的时候也感到很迷茫,因为不明白spring会在何时将实现类的对象注入到你的属性中,对本例来说,spring会在何时调用setCal方法!这个问题的答案可以在spring-test的源代码中找到,下面让我们进入spring-test的源代码之旅吧….:)
首先我们看看spring-test 包的继承体系:
1. org.springframework.test.ConditionalTestCase.java :该类继承了junit 的TestCase,此类有一个有用的方法isDisabledInThisEnvironment,在你的测试类中可以覆盖它,如果你不想执行某个测试方法,就返回true,在一个测试方法运行前,该方法会被自动调用,以决定当前测试方法是否要执行,这样你就可以只关注你想关注的方法:
2. org.springframework.test.AbstractSpringContextTests.java:该类最重要的一点在于它包含有一个静态属性:
此属性保存了spring applicationContext实例,意味着不同的测试类可以共享一个applicationContext,而不必在每个测试类执行时都去重新实例化spring容器
3. org.springframework.test.AbstractSingleSpringContextTests.java:该类覆盖了TestCase类的setUp方法,并且不允许测试类再覆盖,因为该方法包含重要操作—-初始化spring容器,并且为spring的自动注入留下了伏笔—prepareTestInstance方法!作为替代,spring为测试类留了一个初始化入口—onSetUp方法,测试类可以覆盖该方法,为每个测试方法执行自定义初始化操作:
对于tearDown方法,也是一样的,不允许测试类再覆盖,但可以覆盖onTearDown方法,可以执行自定义的销毁操作
同时,此类承担了初始化spring容器的重要任务,测试类可以覆盖getConfigLocations方法为容器的初始化提供配置文件,如: