论坛首页 入门技术论坛

使用spring-mock进行dao集成测试

浏览 32873 次
该帖已经被评为新手帖
作者 正文
   发表时间:2005-03-25  
DAO
在进行dao的集成测试时候,数据清理,察看数据都是比较麻烦的事情,使用Spring-mock.jar可以帮助我们简化着一个过程。我举一个简单的例子,说明一下如何使用spring-mock。

首先是po, hbm.xml, dao, daoimpl没什么好说的:
Customer.java : 

package rst.spring.mock;

import java.io.Serializable;

/** @author Hibernate CodeGenerator */
public class Customer implements Serializable {

    /** identifier field */
    private Long id;

    /** nullable persistent field */
    private String name;

    /** full constructor */
    public Customer(String name); {
        this.name = name;
    }

    /** default constructor */
    public Customer(); {
    }

    public Long getId(); {
        return this.id;
    }

    public void setId(Long id); {
        this.id = id;
    }

    public String getName(); {
        return this.name;
    }

    public void setName(String name); {
        this.name = name;
    }

}

Customer.hbm.xml :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="rst.spring.mock">
	<class name="Customer" table="customer">
		<id name="id" column="id" type="long" unsaved-value="null">
			<generator class="identity"/>
		</id>
		<property name="name" column="name" type="string"/>
	</class>

</hibernate-mapping>

CustomerDAO :
/*
 * Created on 2005-3-25
 */
package rst.spring.mock;

import org.springframework.dao.DataAccessException;

/**
 * @author rst
 *
 */
public interface CustomerDAO {
    public void add(Customer customer); throws DataAccessException;
}

CustomerDAOImpl :

package rst.spring.mock;

import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate.support.HibernateDaoSupport;

/**
 * Class description.
 *
 * @author rst
 */
public class CustomerDAOHibernateImpl extends HibernateDaoSupport implements CustomerDAO{
    
    public void add(Customer customer); throws DataAccessException{
        this.getHibernateTemplate();.save(customer);;
    }
}



然后测试的基类SpringDAOTestCase继承自AbstractTransactionalDataSourceSpringContextTests,目前只有一个指定测试用xml文件位置的逻辑。
package rst.spring.mock;

import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;

/**
 * Class description.
 *
 * @author rst
 */
public abstract class SpringDAOTestCase extends AbstractTransactionalDataSourceSpringContextTests { 

  protected String[] getConfigLocations(); { 
    return new String[] { "test.xml" }; 
  } 

} 


接着是我们真正测试的类CustomerDAOTest.java:
package rst.spring.mock;

/**
 * Class description.
 * 
 * @author rst
 */
public class CustomerDaoTest extends SpringDAOTestCase {

    private CustomerDAOHibernateImpl customerDAO;

    protected void onSetUpInTransaction(); throws Exception {
        super.onSetUpInTransaction();;
        //this.setPopulateProtectedVariables(true);;
        customerDAO = (CustomerDAOHibernateImpl); this.applicationContext.getBean("customerDAO");;
    }

    protected void onTearDownInTransaction(); {
        customerDAO = null;
    }

    public void testInsert(); {
        Customer customer = new Customer();;
        customer.setName("javaeye");;
        customerDAO.add(customer);;
        String name = (String); jdbcTemplate.queryForObject("select name from customer where id=?", new Object[]{customer.getId();}, String.class);;
       
        assertEquals(customer.getName();, name);;
    }

}


最后看看配置文件test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<!--
  - Application context definition for Petclinic on Hibernate.
	-->
<beans>

	<!-- ========================= RESOURCE DEFINITIONS ========================= -->
  
	<!-- Configurer that replaces ${...} placeholders with values from a properties file -->
	<!-- (in this case, JDBC-related settings for the dataSource definition below); -->
	<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location"><value>classpath:jdbc.properties</value></property>
	</bean>

	<!-- Local DataSource that works in any environment -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
		<property name="url"><value>${jdbc.url}</value></property>
		<property name="username"><value>${jdbc.username}</value></property>
		<property name="password"><value>${jdbc.password}</value></property>
	</bean>

	<!-- Hibernate SessionFactory -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
		<property name="dataSource"><ref local="dataSource"/></property>
		<property name="mappingResources">
			<value>rst/spring/mock/Customer.hbm.xml</value>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">${hibernate.dialect}</prop>
				<prop key="hibernate.show_sql">true</prop>
			</props>
		</property>
	</bean>

	<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA); -->
	<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
		<property name="sessionFactory"><ref local="sessionFactory"/></property>
	</bean>
	
	<bean id="hibernateTemplate" class="org.springframework.orm.hibernate.HibernateTemplate">
		<property name="sessionFactory"><ref local="sessionFactory"/></property>
	</bean>

	<bean id="customerDAO" class="rst.spring.mock.CustomerDAOHibernateImpl">
		<property name="hibernateTemplate"><ref local="hibernateTemplate"/></property>
	</bean>
</beans>

这个文件很简单,不要忘记transactionManager的配置,Test类会自动装配的。

运行之后,就可以看到应有的结果,并且数据库中不会有数据污染。这个过程主要是开始一个transaction,然后开始你的test方法,执行dao操作,执行sql查询验证结果,最后无论成功失败rollback transaction。
   发表时间:2005-03-28  
怎么看不懂你的 事务阿 ?

我都是这么写的 。

引用
&lt;bean id="employeeManager" parent="txProxyTemplate"&gt;



你那个 事务 声明了 也没用上阿 .
0 请登录后投票
   发表时间:2005-03-29  
事务声明仅仅是给AbstractTransactionalDataSourceSpringContextTests使用的,它会根据类型自动装配,然后根据这个事务配置进行事务的启动, 回滚操作。
0 请登录后投票
   发表时间:2005-03-29  
谢谢。我按照你 这个 做成功了。 但是我还想请教你几个问题:

我现在控制台 提示几个警告和error
引用
ERROR [main] (CommonsLoggingLogSystem.java:42) - ResourceManager : unable to find resource 'VM_global_library.vm' in any resource loader.

WARN [main] (AbstractDependencyInjectionSpringContextTests.java:194) - No bean with name 'jdbcTemplate'

WARN [main] (AbstractDependencyInjectionSpringContextTests.java:194) - No bean with name 'transactionStatus'

WARN [main] (AbstractDependencyInjectionSpringContextTests.java:194) - No bean with name 'managedVariableNames'


不知道为什么会出现这几个警告。

另外一个问题。我看到一些教程 对于这个测试SPRING 下DAO 的数据 保持。问题是  通过DBUTIL 。把数据保存到xml中,然后,测试结束后再 删除 和xml中相同的数据, 而你这里用的是事物回滚 。  我不知道这2种方法 相比较 ,  孰优孰劣?
0 请登录后投票
   发表时间:2005-03-29  
另外一个问题:关于测试的。
引用
    public void testInsert() {
        Customer customer = new Customer();
        customer.setName("javaeye");
        customerDAO.add(customer);
        String name = (String) jdbcTemplate.queryForObject("select name from customer where id=?", new Object[]{customer.getId()}, String.class);
       
        assertEquals(customer.getName(), name);
    }


比如 我 现在 的论坛, 里面 有[ 栏目]下面有[分论坛]下面有[主题] 而主题这个表 里面还有回复,就是说主题和回复放在一个表里面。
  那我现在想测试一下。增加回复功能, 当然 如果测试DAO 还简单些,如果测试的是 Service层,

当我测试 增加回复功能  的时候,
   
public void testInsert(); { 
    	BbsMain bbsBack = new BbsMain();; 
	bbsBack.setTitle("回复标题");;
	bbsBack.setMessage("回复内容");;
	bbsBack.setBbsFen(bbsFen);;	      //设置回复所在分论坛
	bbsBack.setBbsMain(bbsMain);;	  //设置回复所属主题
	bbsBack.setEmployeeInf(employeeInf);;	 //设置发帖人
	bbsBack.setSendTime(new Date(););;	     //设置回复时间
	bbsBack.setIsTopic("回复");;		     //设置是回复,而非主题

    	dao.saveObject(bbsBack);;    	
        assertNotNull(bbsBack.getBbsId(););;
        
        bbsBack =(BbsMain);dao.getObject(BbsMain.class,bbsBack.getBbsId(););;
        assertEquals(bbsBackgetTitle();, "555张三");;
    } 

    我想请问,这时候 ,那些 栏目,分论坛,主题,发帖人这些 PO  怎么 设定呢?        难道 我们要先  save进 这些.然后再用?
    就是 这样
引用

        public void testInsert() {
BbsSubject   bbsSubject  = new BbsSubject ();    //栏目
bbsSubject.setTitle("栏目名称");      //栏目名称
dao.saveObject(bbsSubject);      //增加栏目

BbsFen bbsFen = new BbsFen();
bbsFen.setTitle("分论坛名称");       //分论坛名称
bbsFen.setBbsSubject(bbsSubject);   //设置分论坛所属栏目
dao.saveObject(bbsFen);      //增加分论坛

EmployeeInf employeeInf = new EmployeeInf();        //发帖人
...............

    BbsMain bbsBack = new BbsMain();
bbsBack.setTitle("回复标题");
bbsBack.setMessage("回复内容");
bbsBack.setBbsFen(bbsFen);       //设置回复所在分论坛
bbsBack.setBbsMain(bbsMain);   //设置回复所属主题
bbsBack.setEmployeeInf(employeeInf); //设置发帖人
bbsBack.setSendTime(new Date());      //设置回复时间
bbsBack.setIsTopic("回复");      //设置是回复,而非主题

    dao.saveObject(bbsBack);   
        assertNotNull(bbsBack.getBbsId());
       
        bbsBack =(BbsMain)dao.getObject(BbsMain.class,bbsBack.getBbsId());
        assertEquals(bbsBackgetTitle(), "555张三");
    }


就是说当测试需要的属性 不在是简单的字符串了.而是一些其他的PO .那这些PO .我们要在这里 都建立一遍么?
0 请登录后投票
   发表时间:2005-03-29  
这个只是一个简单的例子,完全可以把dbunit再加进来,dbunit好处就是数据可以分离出来,修改管理都方便。这个时候可以不用dbunit去清理数据,而由spring回滚事务,那样就可以利用到dbunit的好处了。

至于你的service的测试,应该脱离dao进行unit测试,基于接口编程的好处也应该好好用用。
0 请登录后投票
   发表时间:2005-03-29  
rongsantang 写道
这个只是一个简单的例子,完全可以把dbunit再加进来,dbunit好处就是数据可以分离出来,修改管理都方便。这个时候可以不用dbunit去清理数据,而由spring回滚事务,那样就可以利用到dbunit的好处了。

至于你的service的测试,应该脱离dao进行unit测试,基于接口编程的好处也应该好好用用。


不太明白你的意思 ?  dbunit好处就是数据可以分离出来 是什么意思 ? 你为什么 说 这个阿  简单  的例子 。。。。简单不简单  和  用不用 dbunit有关系么 ?

引用
至于你的service的测试,应该脱离dao进行unit测试


是什么意思  ?  我主要想 请教 你 ,那  里面的 PO 是不是都需要手工的去构造出来  ?
0 请登录后投票
   发表时间:2005-03-29  
dbunit可以避免测试对数据造成污染,利用回滚事务可以实现相同目的。
0 请登录后投票
   发表时间:2005-03-30  
zzeric 写道
dbunit可以避免测试对数据造成污染,利用回滚事务可以实现相同目的。


那请问一下。我测试 Service 的时候, 添加回复的时候,需要的 栏目,分论坛,主题等PO 。是不是需要 手工构造出来。就像我写的那样 ? 如果这样,好像比较麻烦阿?
0 请登录后投票
   发表时间:2005-03-30  
我有个问题:模仿上面的例子,我做了个测试类,里面使用了getUsers()方法不能回滚.
我的测试方法:
public void testGetUsers() {
        user = new Jiveuser();
        user.setName("chen");
      
        dao.saveUser(user);
        System.out.println("++++++"+dao.getUsers().size());
        //assertTrue(dao.getUsers().size() >= 1);
      }
当不调用dao.getUsers().size()时事务能正常回滚,我使用的数据库为mysql
后台打印出的log显示正常,就是不能回滚,去掉dao.getUsers().size()就行了
-----------------------------------
test:
    [junit] INFO - AbstractSpringContextTests.loadContextLocations(95) | Loading
config for /WEB-INF/applicationContext*.xml
    [junit] INFO - AbstractTransactionalSpringContextTests.onSetUp(90) | Began t
ransaction: transaction manager=[org.springframework.orm.hibernate.HibernateTran
sactionManager@1efb4be]; defaultCommit=false
    [junit] DEBUG - UserDAOImpl.saveUser(45) | userId set to: 1
    [junit] INFO - AbstractTransactionalSpringContextTests.onTearDown(106) | Rol
led back transaction after test execution
--------------------------------------
我的getUsers()方法
public List getUsers() {
        return getHibernateTemplate().find("from Jiveuser");
    }
请指点
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics