• 2009-06-04

    Junit in action笔记 - [Junit]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://zlfoxy.blogbus.com/logs/40497009.html

    看书时的一些重点记了一下

    这本书是基于3.8版本的junit

    第2章

    核心assertEquals(String message,Object expected,Object actual)

    message 是方便查看出错时的异常信息(这个很有用!)

    注意expected 和actual的位置 千万别搞颠倒了。

     

    第3章 Sampling Test






    3.2.1 测试DefaultController

    在写了一个空测试方法后,最后加入如下代码:
      throw new RuntimeException("implements me");
    为还没实现的测试代码抛出一个异常.避免了该测试通过,提醒你来实现该代码.
    3.2.2 增加处理器.
      先测试增加处理器功能public void addHandler(Request request, 
      RequestHandler requestHandler)
      为实现该测试
      1.需要一个名字已知的request
      2.为检查添加操作是否正常,使用DefaultController's getHandler method:
      RequestHandler getHandler(Request request),(getHandler是protect方法,而测试类与待测类位于同一个包中.)

      方法:
      1.增加一个RequestHandler,引用一个Request.
      2.获得一个RequestHandler,传递的是同一个Request.
      3.检查以下获得的RequestHandler是否就是增加的那一个.

    测试来自何方?
      为创建一个单元测试,需要两种类型的对象:你要测试的领域的对象和同被测试的对象交互的测试对象
      领域对象:该术语用来突出你在应用程序中使用的对象.

    Junit最佳实践:一次只测试一个对象.
    测试类存在于何方?
      初学者两种方案:
      1.把他们作为package中的公有类.
      2.把他们作为test case类的内部类

    Junit最佳实践:选择有意义的测试方法名
      testXxxYyy. Xxx是方法名 Yyy描述了同一个方法测试的不同之处


      测试遵循的步骤:
      1.在开始测试时把环境设置成已知状态(创建对象,获取资源),测试前的状态常称为test fixture.
      2.调用待测试的方法.
      3.确认结果正确,这通常是通过调用一个或多个assert方法来实现.
    3.2.3 处理请求
      public void testProcessRequest() {
      Request request = new TestRequest();
      RequestHandler handler = new TestHandler();

      controller.addHandler(request, handler);

      Response response = controller.processRequest(request);

      assertNotNull("Must not return a null response", response);  
      // the first parameter may be the info u can easily find what's wrong
      // 验证返回的Response对象不是null.下行代码会对该对象调用getClass方法.
      //为防止出现NullPointException异常,使用assertNotNull(String,Object)方法,如果测试失败,那么显示的错误就是有意义且易于理解的
      //如果使用assertNotNull(object),出错时只会显示AssertionFailedError异常并输出stacktrace,诊断起来会比较麻烦.
      assertEquals(TestResponse.class, response.getClass());
     }
     
    Junit最佳实践:在assert调用中解释失败的原因
      用assertNotNull assertTrue assertFalse assertNotNull这些方法时,记得要用第一个参数是String的那个.在断言失败时可以显示一个描述.便于找失败原因.


    分离出初始化逻辑
      重构 Martin Fowler,Refactoring:Improving the Design of Existing Code(1999)
    Junit最佳实践:一个单元测试等于一个测试方法
      不要把多个测试塞进一个方法.1.方法更复杂,可读性更差.2.逻辑变多了,测试更易失败,需要调试的可能性越大.深渊:为测试编写测试.
      每个测试方法都必须尽可能的清晰和专注.所以Junit提供了setup方法,以使测试之间共享fixture,而不必把测试方法组合起来.
    3.3 测试异常处理
    Junit最佳实践:测试任何可能失败的事物
    bean的setter和getter
    3.3.1 模拟异常条件
    3.3.2 测试异常
      1.插入应当抛出异常的语句
      2.在它后面加上fail语句(以防万一没有抛出异常)
      3.捕捉预期的异常,把异常起名为expected,这样阅读者很容易猜出这个异常是预期的.在catch后的处理写assertTrue(true)
      4.一切正常.
    Junit最佳实践:让异常测试易读.
    Junit最佳实践:让测试改善代码.
      一种辨认异常路径的简单方法是检查待测代码中的不同分支路径(if switch try/catch).当开始跟踪这些分支,你有时可能会觉得测试所有路径实在太痛苦了.如果代码难以测试,那么常常也难以使用.当测试表明这是一项糟糕的设计(code smell,http://c2.com/cgi/wiki?CodeSmell),那么应当停下来重构领域代码.
    在有太多分支的情况下,解决方案通常是把大的方法分割成几个较小的方法,或者你也可以修改类的层次结构来更好的表示问题域.其他的情形需要不同的重构.
    测试是你的代码的第一个顾客,"顾客永远是正确的".
    3.4建立测试项目
    Junit最佳实践:同一个包,分离的目录.
    把所有的测试类和待测类都放在同一个包中,但使用平行目录结构.


    第4章 Examining software tests
    测试不是一个最终的目标.
    4.1 单元测试的重要性
    4.1.1 带来更大的测试范围
      能更容易的模拟错误条件
    4.1.2 带来团队协作的可能
      提交代码前 先测试
    4.1.3 防止衰退,减少调试
      好的单元测试能给开发者带来自信.给了开发人员修改现存代码的勇气,不管是为了重构,还是增加或修改特性.
      一组好的测试能减少用调试程序来发现错误的必要.
    Junit最佳实践:重构
      逐步精化.(stepwise refinement)
       
    4.1.4 使得重构可行
    4.1.5 改进实现设计
    4.1.6 当作开发者文档来用
      单元测试可以做为例子来使用.比API文档还强大.
      单元测试必须和工作代码保持同步,所以始终最新.
    4.1.7 非常有趣哦.
      Kent Beck:任何灭有经过自动测试的程序特性等于不存在的特性.
      知道你的短\代码拥有很好的质量而且正在执行你希望它所执行的操作.
      著有:Extreme Programming Explained:Embrace Change(1999)
      Test Driven Developement : By Example(2003)
    4.2 不同种类的测试
    4.2.1 软件测试的4种类型
      四类:
      1.集成测试
      2.功能
      3.压力/负荷测试
      3.验收测试
      有趣的是,作者这里没有把单元测试加进来.
    集成测试: 
    测试对象,服务和子系统如何交互
    环境 描述
    对象如何交互 测试实例化一个或多个对象,然后从一个对象调用另一个对象的方法
    服务如何交互 在应用程序部署于servlet或EJB容器内部时运行测试.应用连接到激活的数据库,或者连接到任何其他外部资源或设备.
    子系统如何交互 层次化的应用可能会有一个前端子系统来实现显示层,还有一个后端子系统来执行业务逻辑.测试可以检验请求是否从前端传递到后端,并且从后端返回正确的响应.
    理想情况下,集成测试应该在单元被编码前就定义好.
    功能测试:
    压力测试:
      JMeter
      JUnitPerf
    验收测试:
      由用户或者是用户的代理人来进行.确保应用程序满足了用户提出的任何要求.
      验收测试是其他所有测试的超集.通常他们从功能和性能测试开始,但他们通常包含了主管的标准像是易用性和观赏性.有时,验收测试可能包含一个由开发者提供的测试子集.这时候的区别是测试是由客户还是QA团队进行的.
    4.2.2 单元测试的三种类型
      逻辑 集成 功能
      1.逻辑 主要检查代码逻辑性.通常只是针对单个方法.
      2.集成 真实环境下(或其一部分)的两个组件相互交互的测试.
      3.功能 不是纯粹的单元测试.StrutsTestCase
    4.3 判断测试质量
      4.3.1 衡量测试覆盖面
      黑盒测试覆盖率和白盒测试覆盖率的比较
      4.3.2 产生测试覆盖情况报告
      Clover (http://www.thecortex.net/clover/) 商业软件 对非商业用途免费(特别对开放源码社区)
      100%的测试覆盖率并不能保证应用程序得到了100%的测试.
      4.3.3 测试交互
       
    4.4 测试驱动开发
    4.4.1 调整周期
      传统的开发周期:编码 测试 (重复) 交付
      TDD:测试 编码 重构 (重复) 交付
      把测试做为方法的第一个客户:把全部注意力集中与API就会变得很简单.先编写测试程序会带来:
      设计代码的方法;
      关于代码如何工作的文档;
      对于代码的单元测试.
    4.4.2 TDD两步走
      TDD核心原则:
      1.在新代码之前写一个失败的自动测试.  
      2.消除重复.(引自 Test Driven Developement : By Example(2003))
    Junit最佳实践:测试先行(如果没有一个错误的测试就不要写任何新代码)
    4.5 在开发周期中的测试
      生命周期被分成4到5个平台:
      1.开发平台. 自动构建.(SCM 公共源码管理系统)
      2.集成平台.(integration platform) 持续集成.
      3.验收平台/压力测试平台(Acceptance platform/stress test platform)
      4.成品前台((pre-)production platform)
    Junit最佳实践:连续的回归测试
      测试系统自动化

    第5章 Automating JUnit
    Ant Maven和Eclipse
    5.1 生命中的一天
    回归测试 - 在已经存在的代码中加入新的代码时以保证代码依然能够正确运行的测试.(regression test)
    5.2 ANT执行测试
    5.2.1 不可缺少的ANT
      配置环境
      系统变量
      新建变量名:ANT_HOME
      变量值:c:\ANT
      变量名:PATH
      加入变量值:%ANT_HOME%\bin;
    5.2.1 ANT目标 项目 属性以及任务
      ant的要素:
      构建文件
      目标
      属性要素

    第6章 Coarse-grained testing with stubs
    6.1 stub简介
      stub这种机制是用来模拟可能存在或还没写完的真实代码产生的行为.
      定义 stub是代码的一部分.在运行时我们用stub替换真正的代码,忽略调用代码的实现.目的是用一个简单一点儿的行为替换一个复杂的行为,从而允许独立的测试代码的某一部分.
       
      一般而言,stub更适合代码中粗粒度的部分.
    6.2 一个HTTP连接的例子



     何时使用Mock objects
    1.真实对象没有确定的行为
    2.真实对象难以配置
    3.真实对象的一些行为难以控制其发生(比如网络错误)
    4.真实对象运行较慢
    5.真实对象具有(或者本身就是)用户界面
    6.测试需要查询对象,但是无法查询真实对象
    7.真实对象尚不存在


    收藏到:Del.icio.us