边城愚人

如果我不在边城,我一定是在前往边城的路上。

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  31 随笔 :: 0 文章 :: 96 评论 :: 0 Trackbacks

        做 java 企业级开发时,我们通常采用三层架构。特别地,如果我们要做的系统的业务逻辑不是很复杂时,我们要处理的不过是 CRUD 操作,这时我们可能将 dao 层与 service 层合并为一层,尽管很多人会这样做,但我仍倾向于将两层分开;因为 service dao 不是一一对应的,从复用及逻辑清晰的角度考虑,应该将它们分开。在三层架构下,对于 web 层, service 层, dao 层我们都该怎么测试?这里我将介绍基于 Spring Hibernate DbUnit 的情况下我的测试方法。由于使用了 Spring ,事务管理就不在 dao ,因此要单独地测试 dao 可能要麻烦一些;另一方面, dao 中的操作大多是简单的,也不是很值得测试。在使用了 Hibernate Spring 的情况下,我们要测试的除了 HQL ,还有其配置文件,我觉得对数据持久化的测试最好定在 service 上。如果 service 业务逻辑复杂的话,与数据持久化无关的业务逻辑(应该写在领域对象中)可以单独测试 ,在保证与数据持久化无关的业务逻辑的正确性下,带上 dao 操作做集成(单元)测试。

      

在使用 Spring 做测试时,推荐测试类继承自 Spring AbstractTransactionalDataSourceSpringContextTests ,这也是官方推荐的做法。 AbstractTransactionalDataSourceSpringContextTests 对测试方法提供了事务管理,同时它的依赖注入特性也方便测试类注入被测试类(但我并不认为它的事务管理是很需要的)。承接于上一篇文章中的例子 ,下面给出测试类 AccountServiceTest。


package  hibernatesample.service;
import  hibernatesample.domain.Account;
import  java.io.File;
import  java.io.InputStream;
import  java.util.List;
import  org.dbunit.IDatabaseTester;
import  org.dbunit.JdbcDatabaseTester;
import  org.dbunit.dataset.IDataSet;
import  org.dbunit.dataset.xml.FlatXmlDataSet;
import  org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import  org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;

public   class  AccountServiceTest  extends  AbstractTransactionalDataSourceSpringContextTests {

    
private  AccountService accountService;
    
private  IDatabaseTester databaseTester;

    
public  AccountService getAccountService() {
        
return  accountService;
    }
    
    
public  AccountServiceTest() throws  Exception{
    
    }

    
public   void  setAccountService(AccountService accountService) {
        
this .accountService  =  accountService;
    }

    @Override
    
protected   void  onSetUp()  throws  Exception {
        databaseTester 
=   new  JdbcDatabaseTester( " com.mysql.jdbc.Driver " ,
                
" jdbc:mysql://localhost/HibernateSample " " root " " 0102 " );
     IDataSet dataSet 
=  getDataSet();
     databaseTester.setDataSet( dataSet );
     databaseTester.onSetup();
    }

    @Override
    
protected   void  onTearDown()  throws  Exception {
        databaseTester.onTearDown();
    }

    
protected  IDataSet getDataSet()  throws  Exception {
        String path 
=   " hibernatesample " + File.separator + " dao " + File.separator + " dataset " + File.separator + " Account.xml " ;
        InputStream in 
=   this .getClass().getClassLoader().getResourceAsStream(path);
        
return   new  FlatXmlDataSet(in);
    }
    

    @Override
    
protected  String[] getConfigLocations() {
        
        
return   new  String[]{ " classpath:service-applicationContext.xml " };
    }
    
    
public   void  testInsert() {
        Account a 
=   new  Account();
        a.setName(
" aa " );
        accountService.insertAccount(a);
        List
< Account >  l  =  accountService.findAllAccount();
        assertEquals(
3 , l.size());
        Account b 
=  l.get( 2 );
        assertEquals(
" aa " , b.getName());
    }

    
public   void  testFindAll() {
        List
< Account >  l  =  accountService.findAllAccount();
        assertEquals(
2 , l.size());
        Account a 
=  l.get( 0 );
        assertEquals(
new  Long( 1 ), a.getId());
        assertEquals(
" kafka " , a.getName());
        Account b 
=  l.get( 1 );
        assertEquals(
new  Long( 2 ), b.getId());
        assertEquals(
" 0102 " , b.getName());
    }
}

        由于 AccountServiceTest 继承了 AbstractTransactionalDataSourceSpringContextTests ,因此使用 D b Unit 时就不能继承 DBTestCase ,这里采用的方法就是在 onSetUp() 中实现数据集的装入。由于 AbstractTransactionalDataSourceSpringContextTests 最第 N 个顶层的父类继承于 Junit ,所以 onSetUp() 将在 SetUp() 中被调用,默认的 onSetUp() 实现为空; onTearDown() 的原理和 onSetUp() 相似。由于 AbstractTransactionalDataSourceSpringContextTests 具有依赖注入的特性,所以被测试对象 accountService 可以通过 setter 方法获得;当然,我们也可以在构造函数中通过 Bean 工厂获得 accountService protected String[] getConfigLocations() 返回的数组为 Spring Beans 配置文件的位置。

        对于与测试相关的其他类,这里就不给出了。通过使用 DbUnit ,我觉得测试持久化操作时方便了许多。不爽的地方在于,在使用了 Spring Hibernate 的情况下,测试一个方法有些耗时,这自然不单单是 DbUnit 的问题。但如果我将 dao service 的测试放在一起来做,这种耗时也只能忍着。再说一下 web 层的测试,我当前使用的 web 框架是 Webwork ,在测试 Action 的时候,对于 Web 请求之类使用 Mock ,对于 Service 的调用有时 Mock 有时真实调用。 Mock 的好处是耗时能少一些,但写 Mock 代码也很繁琐,而对 service Mock 有时本身就失掉了测试的意义。

posted on 2007-06-14 09:18 kafka0102 阅读(1464) 评论(0)  编辑  收藏 所属分类: TDD

只有注册用户登录后才能发表评论。


网站导航: