Spring 2.5 TestContext 测试框架用于测试基于 Spring 的程序,TestContext 测试框架和低版本 Spring 测试框架没有任何关系,是一个全新的基于注解的测试框架,为 Spring 推荐使用该测试框架。
Spring 2.5 相比于 Spring 2.0 所新增的最重要的功能可以归结为以下 3 点:
Spring 推荐开发者使用新的基于注解的 TestContext 测试框架,本文我们将对此进行详细的讲述。
低版本的 Spring 所提供的 Spring 测试框架构在 JUnit 3.8 基础上扩展而来,它提供了若干个测试基类。而 Spring 2.5 所新增的基于注解的 TestContext 测试框架和低版本的测试框架没有任何关系。它采用全新的注解技术可以让 POJO 成为 Spring 的测试用例,除了拥有旧测试框架所有功能外,TestContext 还添加了一些新的功能,TestContext 可以运行在 JUnit 3.8、JUnit 4.4、TestNG 等测试框架下。
在拙作《精通 Spring 2.x — 企业应用开发详解》一书中,笔者曾经指出如果直接使用 JUnit 测试基于 Spring 的程序,将存在以下 4 点明显的不足:
//加载spring配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); //用getBean()方法获取spring配置文件里定义过的bean,这里不能用注解的方式获得 customerService = (CustomerService)applicationContext.getBean("customerService");
Spring 测试框架是专门为测试基于 Spring 框架应用程序而设计的,它能够让测试用例非常方便地和 Spring 框架结合起来,以上所有问题都将迎刃而解。
这里需要增加了spring-test-2.5.6.jar和junit-4.4.jar两个用于测试的包!
这里尤其要说明一下,由于我们使用注解方式自然要用到JUnit-4.X系列,而Sring-Test对于JUnit有个累人的要求,JUnit的版本必须是4.4,不支持高版本(如4.5、4.7等)。否则,会产生java.lang.ClassNotFoundException: org.junit.Assume$AssumptionViolatedException异常。所以当没有JUnit4.4或其它相关的测试环境时,就导入junit-4.4.jar包
实例:
1 实体类User.java
package org.lab24.entity; import java.io.Serializable; public class User implements Serializable{ public User(){ } private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
对应的hibernate配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="org.lab24.entity"> <class name="User" table="user"><!-- 因为怕group为关键字,所以改一下 --> <id name="id"> <generator class="native"/> </id> <property name="name" type="string" length="50"/> </class> </hibernate-mapping>
2 接口类:
package org.lab24.service; import java.util.List; import org.lab24.entity.User; public interface UserService { public void save(User user); public List<User> getAllUsers(); }
3 实现类:
package org.lab24.serviceImpl; import java.util.List; import javax.annotation.Resource; import org.hibernate.SessionFactory; import org.lab24.entity.User; import org.lab24.service.UserService; import org.springframework.transaction.annotation.Transactional; //数据库操作一般要开启事业,不然抛异常 @Transactional public class UserServiceImpl implements UserService{ @Resource SessionFactory sessionFactory; public List<User> getAllUsers() { return sessionFactory.getCurrentSession().createQuery("from User").list(); } public void save(User user) { sessionFactory.getCurrentSession().persist(user); } }
4 测试类:
package org.lab24.junit.test; import java.util.Iterator; import java.util.List; import javax.annotation.Resource; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.lab24.entity.User; import org.lab24.service.UserService; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration(locations = "classpath:applicationContext.xml") @RunWith(SpringJUnit4ClassRunner.class) //@Transactional /* * 这里在注意的是,在spring配置文件里配置事务管理器(org.springframework.orm.hibernate3.HibernateTransactionManager)时, * 当用的bean名字不是transactionManager,如配置成:<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">时, * 那么就要在这里再加上@TransactionConfiguration(transactionManager = "txManager"),不然抛出异常,找不到默认transactionManager */ //@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true) public class UserServiceImplTest extends AbstractTransactionalJUnit4SpringContextTests{ @Resource private UserService userService; @BeforeClass public static void setUpBeforeClass() throws Exception { //用spring2.5测试框架就不用下面的方式来初始化spring容器 // ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); } @Test public void testGetAllUsers() { List<User> users = userService.getAllUsers(); Iterator iterator = users.iterator(); User temp; while(iterator.hasNext()){ temp = (User) iterator.next(); System.out.println("ID:" + temp.getId() + " name:" + temp.getName()); } } @Test public void testSave() { User user = new User(); user.setName("binge"); userService.save(user); } }
5 spring配置文件applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <context:annotation-config/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="org.gjt.mm.mysql.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/www?useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value=""/> <!-- 连接池启动时的初始值 --> <property name="initialSize" value="1"/> <!-- 连接池的最大值 --> <property name="maxActive" value="500"/> <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 --> <property name="maxIdle" value="2"/> <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 --> <property name="minIdle" value="1"/> </bean> <!-- 下面是用hiberanate的二级缓存的配置,先生成sessionFactory,再将数据源(上面配好的),注入到这里的name=dataSource这里来--> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 下面完成hiberate的配置映射文件,它可以有多条的映射文件列表 --> <property name="mappingResources"> <list> <value>org/lab24/entity/User.hbm.xml</value> </list> </property> <!-- 下面是对hibernate的属性的设置 --> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQL5Dialect hibernate.hbm2ddl.auto=update hibernate.show_sql=true<!-- 测试时用true来看hibernate的操作过程,当发时,要改为false --> hibernate.format_sql=true hibernate.cache.use_second_level_cache=true<!-- 使用二级缓存 --> hibernate.cache.use_query_cache=false hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider </value> </property> </bean> <!-- 下面是配置事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/><!-- 将上面的(ref="sessionFactory")交由事务管理器(name="sessionFactory")来管理 --> </bean> <!-- 下面是打开注解的支持,并设置了事务管理器 (上面配置的事务管理器)--> <tx:annotation-driven transaction-manager="transactionManager"/> <!-- 下面将bean交给spring容器管理,就可以使用依赖注入的方式来引用bean --> <bean id="userService" class="org.lab24.serviceImpl.UserServiceImpl"/> </beans>
6 这里个使用到了ecache,它的配置文件ehcache.xml:
<?xml version="1.0" encoding="UTF-8"?> <!-- defaultCache节点为缺省的缓存策略 maxElementsInMemory 内存中最大允许存在的对象数量 eternal 设置缓存中的对象是否永远不过期 overflowToDisk 把溢出的对象存放到硬盘上 timeToIdleSeconds 指定缓存对象空闲多长时间就过期,过期的对象会被清除掉 timeToLiveSeconds 指定缓存对象总的存活时间 diskPersistent 当jvm结束是是否持久化对象 diskExpiryThreadIntervalSeconds 指定专门用于清除过期对象的监听线程的轮询时间 --> <ehcache> <diskStore path="D:/cache"/> <defaultCache maxElementsInMemory="1000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="180" diskPersistent="false" diskExpiryThreadIntervalSeconds="60"/> <cache name="cn.itcast.bean.Person" maxElementsInMemory="100" eternal="false" overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="600" diskPersistent="false"/> </ehcache>