针对Spring某个类及方法的单元测试,结合单元测试框架(比如JUnit)和Mock的框架(比如EasyMock)就足以完成,当前Bean需要的依赖对象通过Mock创建,隔离所有的依赖,不需要使用到Spring IoC容器。但实际开发中所进行的Spring测试并不是完全意义上的单元测试,而是依赖于容器的测试。
Spring提供的测试框架严格意义上是侧重集成测试的框架,这在Spring官方文档中有明确的区分。但Spring针对单元测试提供了一些支持,包括用于单元测试的一些共用方法和模拟类,这些方法和模拟类,可以使用在一般应用和Web应用中,让测试变得非常方便。
JUnit中加入Spring容器进行测试
结合单元测试框架和Mock框架基本可以对Spring进行单元测试,比如JUnit+EasyMock的组合。在JUnit的框架下,使用EasyMock模拟依赖对象对某个组件类或服务类进行脱离容器的单元测试。
如果要结合容器进行集成测试,在测试类中的固件初始化时(比如@Before注解方法)初始化容器后获取需要的Bean实例进行测试,以JUnit4中初始化容器进行测试的代码示例如下:
public class JunitSpringTest { //单元测试类
private ApplicationContext context; //定义上下文变量
@Before //测试环境初始化注解
public void initSpring() { //环境初始化方法
context = new ClassPathXmlApplicationContext("applicationContext.xml");//初始上下文
}
@Test //注解测试方法
public void testMethod1() { //测试方法
HelloBean bean1 = (HelloBean)context.getBean("bean1"); //从容器获取bean实例
}
}
以上在initSpring()方法中,通过ClassPathXmlApplicationContext初始化容器后就可以从容器中获取Bean进行测试。上面的代码段是较为常见的Spring测试示例,虽然可以达成测试效果,但是存在着如下问题:
频繁初始化容器,开销大、效率低且浪费资源
在JUnit4中,@Before注解在每个标准@Test方法之前都会执行,这就意味着这个测试类中有多少个@Test标识的方法,Spring容器就会被重复化初始多少次。如果容器在初始化时要加载ORM映射和数据源,这笔开销还是很可观的。这个问题虽然可以通过使用@BeforeClass注解修改成类层级的初始化,但是在整个项目使用Maven进行批量测试时,对应每个测试类,都会初始化一个新的容器。
这种效果可以在Eclipse使用Maven批量测试进行验证。新建两个测试类,打印ApplicationContext对象的id,可以看到每个测试类的应用上下文都不一样的,验证的代码如下:
public class JUnitSpring1Test { //测试类
private static ApplicationContext context; //静态应用上下文
@BeforeClass //类层级环境初始化注解
public static void initSpring() { //类层级环境初始化
context = new ClassPathXmlApplicationContext("applicationContext.xml");//上下文
}
@Test //注解测试方法
public void testMethod() { //测试方法
System.out.println("JUnitSpring1Test, applicationContext=" + context.toString());
}
}
测试代码繁琐、冗余
对每个Bean的测试都要先通过getBean()方法从容器中先获取对应的实例,之后做强制类型转换之后方可使用和测试。在涉及多个Bean的集成测试的时候,这样重复额外的代码会极大的影响测试效率。
在数据持久化处理上不便捷
在开发时候的单元测试,或是使用工具批量的单元测试,很多状况希望测试方法不要将数据操作持久化到数据库中。虽然可以在方法层级上添加事务的处理,但是针对测试的特别改动有可能出现忘记回退而影响实际的功能。
针对上面那些问题,Spring提供了专门的测试模块来简化测试工作和加快测试的效率。
Spring测试模块
Spring提供了通用的、注解驱动的测试模块(spring-test)辅助进行Spring相关的测试。spring-test支持结合JUnit或TestNG框架来进行单元测试和集成测试。spring-test的测试模块需要导入,Maven的导入方式直接在pom.xml中加入依赖项,类似:
<dependency>
<groupId>org.springframework</groupId> <!—组名
<artifactId>spring-test</artifactId> <!—组件名
<version>5.0.8.RELEASE</version> <!—版本
</dependency>
此外,Spring是结合JUnit或TestNG进行测试,所以需要确保对应的测试框架导入。
spring-test测试模块的代码目录结构如图1所示