spring 2.5 TestContext 测试框架

大多同事都已经养成用junit写单元测试的习惯,但junit在测试spring 时,存在一些不足!

1.   Spring 容器多次初始化问题
根据 JUnit 测试用例的调用流程,每执行一个测试方法都会重新创建一个测试用例实例并调用其 setUp() 方法。由于在一般情况下,我们都在 setUp() 方法中初始化 Spring 容器,这意味着测试用例中有多少个测试方法,Spring 容器就会被重复初始化多少次

2.   用硬编码方式手工获取 Bean

在测试用例中,我们需要通过 ApplicationContext.getBean("bean id") 的方法从 Spirng 容器中获取需要测试的目标 Bean,并且还要进行造型操作。

 

3.  数据库现场容易遭受破坏

测试方法可能会对数据库记录进行更改操作,破坏数据库现场。虽然是针对开发数据库进行测试工作的,但如果数据操作的影响是持久的,将会形成积累效应并影响到测试用例的再次执行。举个例子,假设在某个测试方法中往数据库插入一条 ID 为 1 的 t_user 记录,第一次运行不会有问题,第二次运行时,就会因为主键冲突而导致测试用例执行失败。所以测试用例应该既能够完成测试固件业务功能正确性的检查,又能够容易地在测试完成后恢复现场.

 

4. 不容易在同一事务下访问数据库以检验业务操作的正确性

当测试固件操作数据库时,为了检测数据操作的正确性,需要通过一种方便途径在测试方法相同的事务环境下访问数据库,以检查测试固件数据操作的执行效果。如果直接使用 JUnit 进行测试,我们很难完成这项操作。

 

Spring 测试框架是专门为测试基于 Spring 框架应用程序而设计的,它能够让测试用例非常方便地和 Spring 框架结合起来.

 

下面我们看下如何使用:

1.    加jar包:
如果你使用的是spring2.5.6,请把\spring-framework-2.5.6\dist\modules\spring-test.jar   copy到你的web项目的lib下。

把Juint4.4以上的jar包copy进web-info下的lib中。一定要注意是4.4以上的版本才支持。

 

2.    写测试基类,要从AbstractTransactionalJUnit4SpringContextTests继承

package cn.xxt.jsr250.action;

import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;

@ContextConfiguration(locations={"/applicationContext.xml","/cn/xxt/jsr250/action/beans.xml"})
public class AbstractBaseTransactionalSpringContextTests extends AbstractTransactionalJUnit4SpringContextTests {

}

 

备注:如果要引入多个配置文件,如同代码中所写,如果只有一个

//@ContextConfiguration(locations="/applicationContext.xml")

 

3.  写具体的测试类,继承测试基类

package cn.xxt.jsr250.action;

import javax.annotation.Resource;

import org.junit.Test;

import cn.xxt.jsr250.domain.ExamUser;
import cn.xxt.jsr250.service.ExamUserService;

/**
 * spring 单元测试
 * @author   zhaoguoli
 * @version  1.0  2011-10-9下午07:07:33 create
 */
public class ExamUserSaveActionTest extends
		AbstractBaseTransactionalSpringContextTests {
	/**
	 * 备注:此处可以使用Resource 和 Autowired 注解
	 */
	@Resource
	private ExamUserService examUserService;
	
	/**
	 * junit 4.0 以上版本的单元测试
	 */
	@Test
	public void execute(){

		ExamUser examUser = new ExamUser();
		
		examUser.setName("123456");
		examUser.setAge(0);
		
		examUserService.saveExamUser(examUser);
		
	}

}

 

备注: 运行后查看日志

INFO 2011-10-09 19:10:23,906 Loading XML bean definitions from class path resource [applicationContext.xml] [org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:323)] 
INFO 2011-10-09 19:10:24,312 Loading XML bean definitions from class path resource [cn/xxt/jsr250/action/beans.xml] [org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:323)] 
INFO 2011-10-09 19:10:24,375 Refreshing org.springframework.context.support.GenericApplicationContext@1820dda: display name [org.springframework.context.support.GenericApplicationContext@1820dda]; startup date [Sun Oct 09 19:10:24 CST 2011]; root of context hierarchy [org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:411)] 
INFO 2011-10-09 19:10:24,375 Bean factory for application context [org.springframework.context.support.GenericApplicationContext@1820dda]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1431340 [org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:426)] 
INFO 2011-10-09 19:10:24,484 Loading properties file from class path resource [frameworkconfig/jdbc/MySQL.properties] [org.springframework.core.io.support.PropertiesLoaderSupport.loadProperties(PropertiesLoaderSupport.java:178)] 
INFO 2011-10-09 19:10:24,578 Loaded JDBC driver: com.mysql.jdbc.Driver [org.springframework.jdbc.datasource.DriverManagerDataSource.setDriverClassName(DriverManagerDataSource.java:155)] 
INFO 2011-10-09 19:10:25,406 Began transaction (1): transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@16f144c]; rollback [true] [org.springframework.test.context.transaction.TransactionalTestExecutionListener.startNewTransaction(TransactionalTestExecutionListener.java:259)] 
INFO 2011-10-09 19:10:25,484 Rolled back transaction after test execution for test context [[TestContext@c2b2f6 testClass = ExamUserSaveActionTest, locations = array<String>['classpath:/applicationContext.xml', 'classpath:/cn/xxt/jsr250/action/beans.xml'], testInstance = cn.xxt.jsr250.action.ExamUserSaveActionTest@737371, testMethod = execute@ExamUserSaveActionTest, testException = [null]]] [org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:279)] 
INFO 2011-10-09 19:10:25,500 Closing org.springframework.context.support.GenericApplicationContext@1820dda: display name [org.springframework.context.support.GenericApplicationContext@1820dda]; startup date [Sun Oct 09 19:10:24 CST 2011]; root of context hierarchy [org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:815)] 

 


 倒数第二行 执行了rolled back

且记:此处跟 数据库本身的事务隔离级别有关系,如mysql  设置的  innodb,会回滚,如果是myisam 不会回滚。同事可以看下数据库到底有没有增加记录。

 

 

总结:其实比较简单,五步区

(1)创建一个扩展自AbstractTransactionalJUnit4SpringContextTests的类,该基类是Spring2.5为方便在JUnit4环境进行事务测试的类,它还提供了一个simpleJdbcTemplate属性让你可以方便地操控数据库表,便于对测试数据进行有效的操作;
(2)用@ContextLocation注解指定你要加载的Spring配置信息所在的位置;(默认的加载文件信息请参阅Spring Documentation);
(3)用@Autowired或@Resource注解注入你的Service接口,@Autowrired是指按类型将Spring Bean注入;而@Resource则按名称将Spring Bean注入。
(4)用@Before准备待测试的数据,如果我们的数据库表结构没有任何数据,则可以在这里预先插入记录,以便进行单元测试,当整个测试完成后,这些数据都不会被保留在数据库中。
(5)在需要进行测试的方法上使用JUnit4.4提供的@Test注解进行标示;

你可能感兴趣的:(context)