使用 Spring 2.5 TestContext 测试DAO层
资源准备: mysql5.0 spring-2.5 hibernate-3.2 junit-4.jar
创建表
DROP TABLE IF EXISTS `myproject`.`boys`; CREATE TABLE `myproject`.`boys` ( `id` bigint(20) NOT NULL auto_increment, `phone` varchar(20) default NULL, `sex` varchar(2) default NULL, `address` varchar(255) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
创建相关配置文件:
(1)applicationContext-resources.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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" 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/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!--
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc.properties</value> </list> </property> </bean> --> <context:property-placeholder location="classpath:jdbc.properties" /> <!-- =====使用dbcp 连接池 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" /> <!-- Hibernate SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" p:dataSource-ref="dataSource" p:mappingResources="testHibernate.hbm.xml"> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> ${hibernate.dialect} </prop> <prop key="hibernate.show_sql"> ${hibernate.show_sql} </prop> <!--<prop key="hibernate.generate_statistics"> ${hibernate.generate_statistics} </prop> --> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory" /> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="find*" read-only="true" /> <tx:method name="get*" read-only="true" /> <!-- 所有抛出异常都要回滚 --> <tx:method name="*" rollback-for="Throwable" /> </tx:attributes> </tx:advice> <!-- com.jmesa.test.service包下面(包括子包)后缀为Service的所有bean --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* com.jmesa.test.service..*Service.*(..))" /> <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/> </aop:config> </beans>
(2) applicationContext-dao.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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" 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/jee htp://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean name="boysDAO" class="com.jmesa.test.dao.hibernate.BoysDAOImpl" autowire="byName"></bean> </beans>
(3)jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost/myproject?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf-8 jdbc.username=root jdbc.password=root hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect hibernate.show_sql=true
(4) boys 实体的hibernate配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping auto-import="true" default-lazy="false"> <class name="com.jmesa.test.model.Boy" table="boys"> <id name="id" column="id" type="long"> <generator class="identity"></generator> </id> <property name="phone" column="phone"></property> <property name="sex" column="sex"></property> <property name="address"></property> </class> </hibernate-mapping>
(5)创建BoysDAO 接口
package com.jmesa.test.dao; import java.util.List; import com.jmesa.test.common.EntityFilters; import com.jmesa.test.common.EntitySorts; import com.jmesa.test.model.Boy; public interface BoysDAO { /** * * @param boy * 域对象 */ public void save(Boy boy); /** * 更新boy数据 * * @param boy */ public void update(Boy boy); /** * 依据id值获得boy域对象 * * @param id * @return */ public Boy get(String id); /** * 获得所有boy域对象 * * @return */ public List<Boy> getAll(); /** * 依据boy 属性条件查询boy列表 * * @param phone * 空或者null值将不作为查询条件 * @param sex * 空或者null值将不作为查询条件 * @return */ public List<Boy> queryBoys(String phone, String sex); }
(6)BoysDAO 接口实现类:
开始测试:
package com.jmesa.test.dao.hibernate; import java.sql.SQLException; import java.util.List; import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Property; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import com.jmesa.test.dao.BoysDAO; import com.jmesa.test.model.Boy; public class BoysDAOImpl extends HibernateDaoSupport implements BoysDAO { public Boy get(String id) { return (Boy) this.getHibernateTemplate().load(Boy.class, id); } public List<Boy> getAll() { return queryBoys(null, null); } public List<Boy> queryBoys(String phone, String sex) { DetachedCriteria query = DetachedCriteria.forClass(Boy.class); if (phone != null && !phone.equals("")) { query.add(Property.forName("phone").eq(phone)); } if (sex != null && !sex.equals("")) { query.add(Property.forName("sex").eq(sex)); } return this.getHibernateTemplate().findByCriteria(query); } public void save(Boy boy) { this.getHibernateTemplate().save(boy); } public void update(Boy boy) { this.getHibernateTemplate().update(boy); } }
基于AbstractTransactionalDataSourceSpringContextTests 创建测试基类:
package com.jmesa.test.integrateTest; import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests; public class BaseDataSourceSpringContextIntegrationTest extends AbstractTransactionalDataSourceSpringContextTests { //加载spring配置文件,其路径在classpath的根目录下 private static final String[] configFiles = new String[] { "applicationContext-resources.xml", "applicationContext-dao.xml" }; //设置dao类的注入方式,默认为类型注入,此处改为名称注入 public BaseDataSourceSpringContextIntegrationTest() { this.setAutowireMode(AUTOWIRE_BY_NAME); } //通过此方法提供spring配置文件 protected String[] getConfigLocations() { return configFiles; } }
BoysDAO的测试类:
package com.jmesa.test.integrateTest; import java.util.List; import org.junit.Assert; import org.junit.Test; import com.jmesa.test.common.EntityFilters; import com.jmesa.test.common.EntitySorts; import com.jmesa.test.dao.BoysDAO; import com.jmesa.test.model.Boy; /** * @author jack */ public class BoyDAOTest extends BaseDataSourceSpringContextIntegrationTest { private BoysDAO boysDAO; public BoyDAOTest(){ } /** * 必须要提供变量boysDAO的setter方法,这样注入才会成功 */ public void setBoysDAO(BoysDAO boysDAO) { this.boysDAO = boysDAO; } @before public void initialize(){ } @after public void destroy(){ } @Test public void testGetAll(){ int count = this.countRowsInTable("boys"); Assert.assertEquals(boysDAO.getAll().size(),count); } @Test public void testQueryBoys(){ Assert.assertEquals(0,boysDAO.queryBoys("www", "wwww").size()); Assert.assertEquals(1,boysDAO.queryBoys("eee", "33").size()); } @Test public void testSave(){ int boysCount = this.countRowsInTable("boys"); String phone ="13401108995"; String sex = "1"; String address = "南京路"; Boy boy = new Boy(); boy.setPhone(phone); boy.setSex(sex); boy.setAddress(address); boysDAO.save(boy); Assert.assertEquals(boysCount+1, this.countRowsInTable("boys")); } @Test public void testGetBoysCountWithFilter(){ EntityFilters entityFilters = new EntityFilters(); int count = boysDAO.getBoysCountWithFilter(entityFilters); Assert.assertEquals(20, count); EntityFilters entityFilters1 = new EntityFilters(); entityFilters1.addFilter("phone", "342432"); int size = entityFilters1.filterSize(); int count1 = boysDAO.getBoysCountWithFilter(entityFilters1); Assert.assertEquals(1, count1); } @Test public void testGetBoysWithFilterAndSort(){ EntityFilters entityFilters = new EntityFilters(); //entityFilters.addFilter("phone", "342432"); EntitySorts entitySorts = new EntitySorts(); entitySorts.addSort("phone", "desc"); List<Boy> boysList = boysDAO.getBoysWithFilterAndSort(entityFilters, entitySorts, 0, 10); Assert.assertEquals(10, boysList.size()); Boy boy = boysList.get(0); Assert.assertEquals("ww",boy.getPhone() ); } }
此处测试用到了 AbstractTransactionalDataSourceSpringContextTests 的四方面的功能:
1. 加载spring的资源配置文件
2. dao bean 引入测试类
3. 简便的函数使用,如:countRowsInTable
4. 事务自动回滚.
请注意此BoyDAOTest测试类中使用@before,@after修饰的方法在测试中没有被执行, 可能原因是BoyDAOTest 间接继承了TestCase类,要想执行此类方法,必须沿用以前版本的junit的setUp,tearDown
方法,然而AbstractTransactionalDataSourceSpringContextTests 类已经overide此方法,并且加了final修饰,其子类不可以在overide了. 所以加入类似before,after这样的方法,目前还没有想出比较好的办法? 还请大侠们赐教.
漫人生路上,该放下的要放下,往事如过眼烟云,浅笑则安...