`
yimlin
  • 浏览: 137014 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

单元测试实践小结

阅读更多
在系统开发过程种使用单元测试,会带来很多的的好处,最明显为:
When you become convinced of the value of comprehensive unit testing, you’ll find that it begins to influence how you write code, and the frameworks you choose to use。

应用单元测试,首先要解决的是单元测试的关注点
测试的关注点在于测试逻辑,只要有逻辑就要写测试代码。测试的手段就是验证所有被测试方法的所有产出物,包括:
1. 测试方法的返回值
2. 测试方法的执行流程
例如:
public class DomainService {
private static TheDAO dao = new TheDAO ();
public ReturnObject findByCond(String) {
        return (ReturnObject)dao.getBeanByCondition("select * from ReturnObject where cond="+ paramter, ReturnObject.class);
    }
}

在对于测试findByCond方法,有两个测试用例:
A.测传递给TheDAO.getBeanByCondition的参数的正确性,如果参数不是”select * from ReturnObject where cond=?”和ReturnObject.class则返回为null。
B.测返回的对象正确性。
 
特别是第二点,在商业应用上比较常见的。通常有些方法无明显output,通常是执行写表操作的。对于这样的方法就是测试它的执行流程。当然这些方法本身包含逻辑的。
一个简单的解决方法是利用Access Log来实现(虽然这样的测试不多,而写的case代码也看着怪怪的)。
public class ServiceExample{
    private DatabaseDao1 dao1;
    private DatabaseDao2 dao2;
 
    public void noOutputMethod(){
if(...)
            dao1.update(...);
    if(...)
            dao2.delete();
}
}

 
相关的测试代码可以这样:
public class MockDatabaseDao1 implements DatabaseDao1 {
private Map map;
public void setMap(Map map){
     this.map = map;
 }
 
public void update(args){
     map.put("MockDatabaseDao1.update", args);
}
}

   
public class MockDatabaseDao2 implements DatabaseDao2 {
    private Map map;
 
    public void setMap(Map map){
        this.map = map;
    }
 
    public void delete(args){
        map.put("MockDatabaseDao2.delete", args);
}
}

 
public class ServiceExampleTestCase{
    private Map map = new HashMap();
    public void testNoOutputMethod(){
        DaoTest test = new DaoTest();
   DatabaseDao1 dao1 = new MockDatabaseDao1();
   dao1.setMap(map);
   dao2.setMap(map);
   DatabaseDao2 dao2 = new MockDatabaseDao2();
    test.setDao1(dao1);
    test.setDao2(dao2);
    test.noOutputMethod();
    assertEquals(new Boolean(true), new Boolean(map.containsKey("MockDatabaseDao1.update")));
    assertEquals(new Boolean(true), new Boolean(map.containsKey("MockDatabaseDao2.delete"))); 
    }
}
 

例子只测试执行流程,实际实践中还可以验证所有的参数。 
我们还可以考虑利用AOP来改进这个测试方法。then, we needn't to do the same work,each time. We repeat it only once.

讨论完测试的关注点后,需要看看实际面临的具体困难
职责不明确 
   类或类方法的职责不明确,违反SRP原则.一个类或方法处理了本不该有它处理的逻辑,使得单元测试需要关心过多的外部关联类
静态方法
    静态方法使得调用者直接面对实际的服务类,难以通过其他方式替换其实现,也难以扩展
直接访问对象实例
调用者直接实例化服务对象,从而使用服务对象提供的服务.同静态方法一样,直接面对其服务类
J2se和J2ee标准库或者其他类库
    标准类库中有非常多的接口调用使得调用者难以测试 e.g JNDI, JavaMail, JAXP
准备数据及其困难
    编写测试用例需要外部准备大量的数据

针对这些困难,可用解决方法如下: 
重构系统
    对于职责不明确的代码,只有通过重构才可以达到单元测试的目的。
Self-Delegate test pattern
   针对于class的测试,使用自代理测试模式, 使得测试时,可以重写被测试类的一些方法.达到测试的目的.通过extend class override methods来实现。Inner class mock方法也一样。不过这种方法比较别扭
编写Stubs和Mock object 
   1.   接口的mock比较容易,测试时,编写stubs和mock object来辅助测试,是非常重要的技术. Mock object分动态mock和静态mock.采用EasyMock可以很好的实现动态mock。 
   2.  具体类的mock,也很简单,通常利用子类继承的方式实现,利用cglib框架可以很好大达到测试目的。 
   3.  静态方法的mock。静态方法由于是直接面对服务对象,比较麻烦。不过,并非不可以测试,实际我们可以利用classpath的特点来实现。
方法很简单,mock类与建立一个将被mock的类的package,class name以及方法签名完全一样,但方法实现却是mock过的。在运行测试用例时,把mock类打成jar(不一定要这么做), 在配置classpath时确保,该jar的位置在当前class之前,就可以实现替换。代码如下:StaticMock.rar
使用成熟单元测试框架
   除了最基本的Junit外,Opensource提供了很多非常有价值的单元测试框架,熟练使用这些工具,可以提高测试的效率。包括对准备大量的数据,以及j2ee的框架代码。
   现有代码的可选自动化测试工具:
   1. POJO:JUnit, JMock或者EasyMock
   2. Data Object:DDTUnit。准备大量数据。
   3. Dao:DBUnit。初始化数据库。批量产生数据库数据。
   4. EJB: MockEJB或者MockRunner
   5. Servlet:Cactus
   6. Struts:StrutsUnitTest
   7. XML:XMLUnit
   8. J2EE: MockRunner
   9. GUI: JFCUnit, Marathor
   10. Other: JTestCase(采用XML定义测试过程)

分层架构下的单元测试
1 Web层的单元测试
主要测试Controller的数据结构化逻辑
如果View是利用模板引擎的,需要测试页面的控制脚本是否正确。

2 Domain Service的单元测试
包括业务规则和业务流程。
Service有四种参与对象,如下:
   1. Domain Object
   2. Dao对象
   3. 其它Service服务。
   4. 工具类
产出物:
   1. 返回值包括POJO,和结构化的数据(如XML)
   2. 传递给流程节点的参数值。
特点:
   概念上,业务逻辑和业务流程是相对独立的。实际代码,虽然一些业务逻辑是相对独立的。但是有一些业务逻辑与流程合在一起。由于业务逻辑有明确的返回值,业务规则可以独立成一个方法,其是有显示的返回值,这样UnitTest就可以focus在业务规则的测试上。而业务流程通常没有显示的返回值,在很多实践中表现为写表动作,测试比较麻烦。
   同时,不过的实际情况是业务规则和业务流程是合并在一起的。

测试的应覆盖:
1. 返回值包括POJO,或者结构化的数据如XML可以利用XMLUnit来解决。
2. 流程节点的访问,以及传递给流程节点的参数值。即对业务流程的测试,可以使用上面的访问点的方法。

3.Dao的单元测试
第一个面临的问题是:做Dao数据访问层的单元测试时机。another word也就是要不要做单元测试。
几种情况是不用测试的
1. 如果Dao就是简单的CRUD,那么不用测;在未来当我们使用1.5的范型后,这些CRUD只要在父类做一边里就可以了。
2. 如果hbm文件是自动生成的,那也不用测。
以下是要测的情况:
1. 如果hbm文件是手工写的,那么需要你保证hbm的正确性。如何测试,后面再说。
2. 如果Dao中包括了一些组合查询,那么这是一种逻辑,就应该去测;如果Dao的查询还包含了某个排序机制,这个排序逻辑依据的是业务字段,那么也是要测的。(理由是:这些逻辑可以在java代码实现,不过是性能太差了,但是既然java代码的逻辑要测,那么我们没有理由不去测在sql中的逻辑)。

第二个问题如何测试:
0. 测试数据准备
可以将BA准备的数据导出。在利用Excel编辑产生一批数据。
但是每个UnitTest测试本身应该focus一个关注点上,所以每个UnitTest的数据保持在较少的水平上。
另外由于DBUnit导入数据的顺序是依据sheet的顺序的,请注意把所有外键表在前,否则插入数据时,会报外键不存在错误。

1. 数据库的选择
a.可以直接用小组用的开发数据库。优点:现成的, 所有schema都建好了。缺点:目前数据库的数据干净性无法保证,连接速度太慢。
b.使用hsqldb。优点:利用其内存模式,可以随测试程序启动,简单小巧,schema可以自行定义,每人各自一套互不影响。 缺点:无法提供PLSQL支持。出于UnitTest本身的要求,以及性能上考量,大部分情况下,建议使用hsqldb,对于涉及到PLSQL的,需要mock处理。

2.测试hbm
利用hsqldb内存数据库,在setup的时候,利用hibernate的SchemaExport工具类,将hbm导出成数据库的schema,如果有确实有潜在问题,那么测试程序将不通过。

3.测试Dao
很简单了,调用dao程序操作。对于save,update和delete操作的。需要利用原始的connection执行查询验证。对于组合查询的和逻辑排序的,就是一般的做法了。

4.在使用DBUnit时,测试非只读操作时,我们经常会采用 DatabaseOperation.CLEAN_INSERT 策略.在关联表比较多时,效率会很差.因为每次setUp,tearDown时都会重新先Delete,再Insert所有的数据.另外,我们还有一种数据库操作测试的策略,就是使用真实数据库,在每次操作完毕后都回滚事务.

分享到:
评论

相关推荐

    单元测试实践小结(很详细)

    单元测试实践小结单元测试实践小结,很好的一个单元测试实践小结总结,希望对大家有帮助

    单元测试实践小结[5]

    单元测试实践小结[5] 软件测试 7.XML:XMLUnit 8.J2EE:MockRunner 9.GUI:JFCUnit,Marathor 10.Other:JTestCase(采用XML定义测试过程) 分层架构下的单元测试 1Web层的单元测试 主要测试Controller的数据结构化...

    单元测试实践小结[1]

    单元测试实践小结[1]单元测试工具应用单元测试,首先要解决的是单元测试的关注点。测试的关注点在于测试逻辑,只要有逻辑就要写测试代码。测试的手段就是验证所有被测试方法的所有产出物,包括:1.测试方法的返回值2...

    软件单元测试实践小结[2]

    软件单元测试实践小结[2]单元测试代码相关的测试代码可以这样:publicclassMockDatabaseDao1implementsDatabaseDao1{privateMapmap;publicvoidsetMap(Mapmap){this.map=map;}publicvoidupdate(args){map.put(...

    单元测试实践小结[6]

    单元测试实践小结[6]软件测试产出物:1.返回值包括POJO,和结构化的数据(如XML)2.传递给流程节点的参数值。特点:概念上,业务逻辑和业务流程是相对独立的。实际代码,虽然一些业务逻辑是相对独立的。但是有一些业务...

    单元测试实践小结[3]

    单元测试实践小结[3]软件测试例子只测试执行流程,实际实践中还可以验证所有的参数。我们还可以考虑利用AOP来改进这个测试方法。then,weneedn'ttodothesamework,eachtime.Werepeatitonlyonce.讨论完测试的关注点后...

    单元测试实践小结[4]

    单元测试实践小结[4]软件测试编写Stubs和Mockobject1.接口的mock比较容易,测试时,编写stubs和mockobject来辅助测试,是非常重要的技术.Mockobject分动态mock和静态mock.采用EasyMock可以很好的实现动态mock。2....

    单元测试实践小结[7]

    单元测试实践小结[7]软件测试第二个问题如何测试:0.测试数据准备可以将BA准备的数据导出。在利用Excel编辑产生一批数据。但是每个UnitTest测试本身应该focus一个关注点上,所以每个UnitTest的数据保持在较少的水平...

    软件测试--Nunit单元测试

    首先描述软件测试的基本知识,着重叙述单元测试,然后介绍一些单元测试的工具,最后再使用NUnit进行一些实践测试,并进行小结。

    Java测试新技术TestNG和高级概念.part1

    1.5 本章小结 第2章 测试设计模式 2.1 针对失败而测试 2.2 工厂 2.3 数据驱动测试 2.4 异步测试 2.5 测试多线程代码 2.6 性能测试 2.7 模拟和桩 2.8 依赖的测试 2.9 继承和annotation范围 2.10 测试分组 2.11 ...

    Java测试新技术TestNG和高级概念.part2

    1.5 本章小结 第2章 测试设计模式 2.1 针对失败而测试 2.2 工厂 2.3 数据驱动测试 2.4 异步测试 2.5 测试多线程代码 2.6 性能测试 2.7 模拟和桩 2.8 依赖的测试 2.9 继承和annotation范围 2.10 测试分组 2.11 ...

    Pro .NET Best Practices .net最佳实践 英文版

    1.4 小结 第2章 .NET实践领域 2.1 从内部挖掘 2.1.1 技术债 2.1.2 缺陷跟踪系统 2.1.3 反思分析 2.1.4 前瞻性分析 2.2 应用程序生命周期管理 2.3 设计模式和开发指南 2.3.1 .NET设计规范 2.3.2 微软的模式和实践...

    《.NET最佳实践》.((美)Stephen Ritchie)

    1.4 小结 13 第2章 .NET实践领域 15 2.1 从内部挖掘 17 2.1.1 技术债 17 2.1.2 缺陷跟踪系统 18 2.1.3 反思分析 19 2.1.4 前瞻性分析 20 2.2 应用程序生命周期管理 20 2.3 设计模式和开发指南 22 2.3.1 ...

    Java SE实践教程 源代码 下载

    1.3 小结 35 第2章 对象无处不在——面向对象的基本概念 37 2.1 讲解 38 2.1.1 什么是面向对象 38 2.1.2 面向对象的基本概念 38 2.1.3 Java对面向对象的支持 41 2.2 练习 42 2.2.1 JavaBeans技术开发可重用...

    Java SE实践教程 pdf格式电子书 下载(一) 更新

    感谢大家的支持,我终于升级了,上传限制得到提升,所以把资源整合下!希望大家一如既往 Java SE实践教程 pdf格式电子书 下载(一) 更新 ...Java SE实践教程 pdf格式电子书 下载(二) 更新 ...13.4 小结 387

    Web前端开发基础:发布整个网站.ppt

    教学内容 3 动手实践 1 单元目标 2 教学内容 4 课堂小结 动手实践 4 课堂小结 1 单元目标 2 教学内容 3 动手实践 独立发布网站,并在局域网内实现浏览成功 ,能够整合与发布网站 。总结发布网站的过程,并申请网站...

    Java SE实践教程 pdf格式电子书 下载(四) 更新

    感谢大家的支持,我终于升级了,上传限制得到提升,所以把资源整合下!希望大家一如既往 Java SE实践教程 pdf格式电子书 下载(一) 更新 ...Java SE实践教程 pdf格式电子书 下载(二) 更新 ...13.4 小结 387

    程序开发原理:抽象、规格与面向对象设计.[美]Barbara Liskov(带详细书签).pdf

    3.6 小结 34 练习 35 第4章 异常 36 4.1 规格 37 4.2 Java异常机制 38 4.3 异常编程 42 4.4 设计问题 43 4.5 防御编程 46 4.6 小结 47 练习 47 第5章 数据抽象 48 5.1 数据抽象的规格 49 5.2 使用数据...

    精通Qt4编程 pdf 中文版 part2

    本书分为三部分。 目录回到顶部↑前言 初级篇 第1章 Qt初步实践 1.1 第一个Qt程序 ...第21章 Qt单元测试框架 附录A Qt安装 附录B Qt集成开发环境 附录C qmake速查 附录D 深入Qt源代码 附录E Qt资源

    精通Qt4编程 pdf 中文版 part3

    本书分为三部分 目录回到顶部↑前言 初级篇 第1章 Qt初步实践 1.1 第一个Qt程序 1.2 使用Qt布局管理器 ...第21章 Qt单元测试框架 附录A Qt安装 附录B Qt集成开发环境 附录C qmake速查 附录D 深入Qt源代码 附录E Qt资源

Global site tag (gtag.js) - Google Analytics