ssh 下dao 层测试

单元测试最佳实践:TestNG与Spring的配置与整合

如果我们用Spring管理程序中的Bean,那么关于单元测试的几个问题需要解决:

  1. 怎样启动单元测试前加载Spring的context
  2. 怎样允许单元测试代码使用mock来取代Spring中配置的bean,比如数据库连接
  3. 测试中怎样维护测试数据的状态

下面简单介绍这三个问题的解决方法。

对第一个问题,首先我们都很清楚在web程序中,运行时的Spring启动可以通过在web.xml里面配置servlet和listener来解决。这个就不另外说明了。那么解决问题的办法分为以下几个:

1. 为测试建立单独的Spring的xml配置文件。这样就允许你为测试单独设置程序运行的依赖。有些对外界环境的依赖,比如JNDI,Data Source,都可以用mock对象来取代。为了生成mock对象,可以写一个工厂类,然后在Spring中使用这个工厂类来生成mock对象。SessionFactory和HibernateTemplate都可以用这种方式mock。

<bean id="hibernateTemplate" class="com.resource.MockFactory" factory-method="createHibernateTemplate"> 
</bean-->

2. 建立一个测试基类,为其加上注解来启动Spring上下文。所有的单元测试可以继承这个类,那么它们在运行时,Spring就会自动加载,测试中需要的依赖也会被加载。TestNG的代码如下:

 
@ContextConfiguration( locations = { "file:src/main/webapp/WEB-INF/application.int.test.spr.xml" } )
public abstract class BaseTest extends AbstractTestNGSpringContextTests {
 
}

这种方式使用JUnit4其实会更方便一些,不过TestNG也没太大的问题。

3. 设置内存数据库供测试中使用。目的是方便、高效。这里举HSQLDB为例,在Spring中配置一下就会自己启动:

 
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
        <property name="url" value="jdbc:hsqldb:mem:."/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>
 
 	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource"><ref local="dataSource"/></property>
		<property name="packagesToScan" value="com.resource.business.model" />
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
			</props>
		</property>
	</bean>
 
	<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
	   <constructor-arg index="0">  
            <ref local="sessionFactory"/>  
        </constructor-arg>  
	</bean>

4. 使用DBUnit维护测试数据。把清空数据库和注入测试数据的代码写在@BeforeTest里(或者如果必要的话也可以在每个测试用例前做,比如@BeforeClass,但如果数据大的话会对性能有影响),这样每次测试前都可以保证数据库是干净的。也可以把维护数据的代码放在一个基类里,比如:

@ContextConfiguration( locations = { "file:src/main/webapp/WEB-INF/application.int.test.spr.xml" } )
public abstract class BaseIntegrationTest extends AbstractTestNGSpringContextTests {
 
	protected DataSourceDatabaseTester tester;
 
	@Autowired
	protected DataSource dataSource;
 
	@BeforeClass
	public void setUpDatabase() throws Exception {
		IDataSet dataSet = this.getDataSet();
 
		if (dataSet == null) {
			return;
		}
 
		tester = new DataSourceDatabaseTester(dataSource);
 
		tester.setSetUpOperation(DatabaseOperation.CLEAN_INSERT);
		tester.setDataSet(dataSet);
		tester.onSetup();
	}
 
	@AfterClass
	public void tearDownDatabase() throws Exception {
		if (tester != null) {
			tester.onTearDown();
		}
	}
 
	protected IDataSet getDataSet() throws Exception {
		return new FlatXmlDataSetBuilder().build(BaseIntegrationTest.class.getResourceAsStream("/dataset.xml"));
	}
 
}

 



转自: http://blog.csdn.net/blackchoc/article/details/5711860

 

项目中用到了testNG作为单元测试工具,至于testNG对比junit有啥好处不太清楚,至少从程序员写testcase来说似乎和junit 4.x并没有太大的区别。但是据说和一些测试工具整合的时候比较方便。ok,这不是重点。

 

Spring专门为Junit testNG提供了一套测试集成接口类——AbstractSpringContextTests类,对于testNG就是其子类:AbstractTestNGSpringContextTests。Spring和testNG整合后,进行单元测试的时只要test类继承该类,就可以方便的使用spring注入。实现了spring和testNG的无缝整合,我们可以像写普通类那样测试被spring IoC容器所管理的类(否则我们必须在开始执行单元测试前重新加载Spring beanfactory,再用getBean("xxx")的方式获取IoC容器中类。)

 

除此以外,对测试类spring beanfactory缓存,使得多个测试类之间可以共享同一个的beanfactory实例,从而减少了重复生成beanfactory,提高了运行效率。

 

继承该类的测试用例在spring管理的事务中进行,测试完后对数据库的记录不会造成任何影响。你对数据库进行一些操作后,它会自动把数据库回滚,这样就保证了你的测试对于环境没有任何影响

 

集成代码如下

 

Java代码   收藏代码
  1. @ContextConfiguration   
  2. (locations={"applicationContext.xml"})  
  3. public class TestUser extends AbstractTestNGSpringContextTests{  
  4.    
  5.  @Autowired  
  6.  UserService userService;  
  7.    
  8.  @Test  
  9.  public void test_save_user(){  
  10.   User user = new User();  
  11.   user .setPassword("123456");  
  12.   user .setSex(1);  
  13.   user .setPartyName("test1");  
  14.   user .setEmail("aa@bb.com");  
  15.   userService.save(user);  
  16.  }  
  17.    
  18.  @Test  
  19.  public void test_inject_factory(){  
  20.   Assert.assertNotNull(userService);  
  21.  }  
  22. }  

 

 

 

其中最重要的就是@ContextConfiguration。默认的从classpath目录下读取applicationContext.xml作为spring的启动配置文件(对应ClassPathXmlApplicationContext?)。
等同于(locations={"classpath:applicationContext1.xml"})。因此必须确保spring的配置文件在classpath中。
如果有多个spring配置,用逗号进行分隔(locations={"applicationContext.xml", "/applicationContex_transaction.xml"})

 

另外一种采用filepath定位spring配置文件(对应FileSystemXmlApplicationContext?).
比如在web项目中将相应的配置文件放到WEB-INF目录下"file:WebRoot/WEB-INF/config/applicationContext.xml",或者可以指定绝对路径。

 

 

 

实际问题:

项目中,将配置放在了web-inf/config/目录下对应的xml文件中,但是又在xml文件中对web-inf/config/properties/目录下的几个包括log4j.properties在内的几个properties文件进行了引用。

 

如果使用file方式指定spring配置文件位置的话,当加载到xml文件中引用的property文件时就会报文件找不到。因为仅仅指定采用file方式读取xml文件,对于对于property文件仍然会去classpath搜索。

 

 

解决方法

将Webroot加入到项目的classpath目录中。

或者更好的做法是指定在运行testNG测试时,将webroot加入到classpath中。

 

Eclipse中 run/run configuration菜单中进行配置



 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值