首页 | 互联网 | IT动态 | IT培训 | Cisco | Windows | Linux | Java | .Net | Oracle | 软件测试 | C/C++ | 嵌入式开发 | 存储世界 | 服务器
网络设备 | IDC | 安全 | 求职招聘 | 数字网校 | 网页设计 | 平面设计 | 技术专题 | 电子书下载 | 教学视频 | 源码下载 | 搜索 | 博客 | 论坛
中国IT实验室Linux频道
中国IT教育
Google
首页 资讯动态 认证考试 新手入门 核心技术 高级技术 J2EE J2ME Java&XML 开源技术 其他技术 RSS订阅 论坛 专题
您现在的位置: 中国IT实验室 >> Java >> 高级技术 >> 设计模式 >> 正文

追逐代码质量: 决心采用 FIT

  Drools 的规则

  必须在特定于 Drools 的 XML 文件中定义计算折扣的业务规则。例如,清单 8 中的代码段就是一个规则:如果桶数大于 9,小于 50,不是季节性产品,则订单有 5% 的折扣。

  清单 8. BusinessRules.drl 文件的示例规则



<rule-set name="BusinessRulesSample"
          xmlns="http://drools.org/rules"
          xmlns:java="http://drools.org/semantics/java"
          xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
          xs:schemaLocation="http://drools.org/rules rules.xsd
                             http://drools.org/semantics/java java.xsd">
<rule name="1st Tier Discount">
  <parameter identifier="order">
    <class>WholesaleOrder</class>
  </parameter>

  <java:condition>order.getNumberOfCases() > 9 </java:condition>
  <java:condition>order.getNumberOfCases() < 50 </java:condition>
  <java:condition>order.getProductType() == "year-round"</java:condition>

  <java:consequence>      
    order.setDiscount(0.05);
  </java:consequence>
</rule>
</rule-set>




  标记团队测试

  有了 PricingEngine 并定义了应用程序规则之后,可能渴望验证所有东西都工作正确。现在问题就变成,用 JUnit 还是 FIT?为什么不两者都用呢?通过 JUnit 测试所有组合是可能的,但是要进行许多编码。最好是用 JUnit 测试少数几个值,迅速地验证代码在工作,然后依靠 FIT 的力量运行想要的组合。请看看当我这么尝试时发生了什么,从清单 9 开始:


  清单 9. JUnit 迅速地验证了代码在工作


package org.acme.store.discount.engine.junit;

import junit.framework.TestCase;
import org.acme.store.Money;
import org.acme.store.discount.engine.PricingEngine;
import org.acme.store.discount.engine.ProductType;
import org.acme.store.discount.engine.WholesaleOrder;

public class DiscountEngineTest extends TestCase {

  public void testCalculateDiscount() throws Exception{
    WholesaleOrder order = new WholesaleOrder();
    order.setNumberOfCases(20);
    order.setPricePerCase(new Money(10.00));
    order.setProductType(ProductType.YEAR_ROUND);

    PricingEngine.applyDiscount(order);

    assertEquals(0.05, order.getDiscount(), 0.0);
  }

  public void testCalculateDiscountNone() throws Exception{
    WholesaleOrder order = new WholesaleOrder();
    order.setNumberOfCases(20);
    order.setPricePerCase(new Money(10.00));
    order.setProductType(ProductType.SEASONAL);
    
    PricingEngine.applyDiscount(order);

    assertEquals(0.0, order.getDiscount(), 0.0);
  }
}

  还没用 FIT?那就用 FIT!

  在 图 5 的 FIT 表格中有八行数据值。可能已经在 清单 7 中编写了前两行的 JUnit 代码,但是真的想编写整个测试吗?编写全部八行的测试或者在客户添加新规则时再添加新的测试,需要巨大的耐心。好消息就是,现在有了更容易的方法。不过,不是忽略测试 —— 而是用 FIT! 

  FIT 对于测试业务规则或涉及组合值的内容来说非常漂亮。更好的是,其他人可以完成在表格中定义这些组合的工作。但是,在为表格创建 FIT 装备之前,需要给 Money 类添加一个特殊方法。因为需要在 FIT 表格中代表当前货币值(例如,像 $100.00 这样的值),需要一种方法让 FIT 能够认识 Money 的实例。做这件事需要两步:首先,必须把 static parse 方法添加到定制数据类型,如清单 10 所示:


清单 10. 添加 parse 方法到 Money 类


 public static Money parse(String value){
   return new Money(Double.parseDouble(StringUtils.remove(value, '$')));
 }

  Money 类的 parse 方法接受一个 String 值(例如,FIT 从表格中取出的值)并返回配置正确的 Money 实例。在这个示例中,$ 字符被删除,剩下的 String 被转变成 double,这与 Money 中现有的构造函数匹配。

  不要忘记向 MoneyTest 类添加一些测试来来验证新添加的 parse 方法按预期要求工作。两个新测试如清单 11 所示:

 
  清单 11. 测试 Money 类的 parse 方法


 public void testParse() throws Exception{
   Money money = Money.parse("$10.00");
   assertEquals("$10.00", money.toString());
 }

 public void testEquals() throws Exception{
   Money money = Money.parse("$10.00");
   Money control = new Money(10.00);
   assertEquals(control, money);
}

  编写 FIT 装备

  现在可以编写第一个 FIT 装备了。实例成员和方法已经在表 1 和表 2 中列出,所以只需要把事情串在一起,添加一两个方法来处理定制类型:Money。为了在装备中处理特定类型,还需要添加另一个 parse 方法。这个方法的签名与前一个略有不同:这个方法是个对 Fixture 类进行覆盖的实例方法,这个类是 ColumnFixture 的双亲。

  请注意在清单 12 中,DiscountStructureFITparse 方法如何比较 class 类型。如果存在匹配,就调用 Money 的定制 parse 方法;否则,就调用父类(Fixture)的 parse 版本。

  清单 12 中剩下的代码是很简单的。对于图 5 所示的 FIT 表格中的每个数据行,都设置值并调用方法,然后 FIT 验证结果!例如,在 FIT 测试的第一次运行中,DiscountStructureFITlistPricePerCase 被设为 $10.00,numberOfCases 设为 10,isSeasonal 为 true。然后执行 DiscountStructureFITdiscountPrice,返回的值与 $100.00 比较,然后执行 discountAmount,返回的值与 $0.00 比较。


  清单 12. 用 FIT 进行的折扣测试


package org.acme.store.discount;

import org.acme.store.Money;
import org.acme.store.discount.engine.PricingEngine;
import org.acme.store.discount.engine.ProductType;
import org.acme.store.discount.engine.WholesaleOrder;
import fit.ColumnFixture;

public class DiscountStructureFIT extends ColumnFixture {

  public Money listPricePerCase;
  public int numberOfCases;
  public boolean isSeasonal;

  public Money discountPrice() throws Exception {
    WholesaleOrder order = this.doOrderCalculation();
    return order.getCalculatedPrice();
  }

  public Money discountAmount() throws Exception {
    WholesaleOrder order = this.doOrderCalculation();
    return order.getDiscountedDifference();
  }

 /**
  * required by FIT for specific types
  */
  public Object parse(String value, Class type) throws Exception {
    if (type == Money.class) {
      return Money.parse(value);
    } else {
      return super.parse(value, type);
    }
  }

  private WholesaleOrder doOrderCalculation() throws Exception {
    WholesaleOrder order = new WholesaleOrder();
    order.setNumberOfCases(numberOfCases);
    order.setPricePerCase(listPricePerCase);

    if (isSeasonal) {
      order.setProductType(ProductType.SEASONAL);
    } else {
      order.setProductType(ProductType.YEAR_ROUND);
    }

    PricingEngine.applyDiscount(order);
    return order;
  }
}

  现在,比较 清单 9 的 JUnit 测试用例和清单 12。是不是清单 12 更有效率?当然可以 用 JUnit 编写所有必需的测试,但是 FIT 可以让工作容易得多!如果感觉到满意(应当是满意的!),可以运行构建,调用 FIT 运行器生成如图 6 所示的结果:


  图 6. 这些结果真的很 FIT !



  结束语

  FIT 可以帮助企业避免客户和开发人员之间的沟通不畅、误解和误读。把编写需求的人尽早 带入测试过程,是在问题成为开发恶梦的根源之前发现并修补它们的明显途径。而且,FIT 与现有的技术(比如 JUnit)完全兼容。实际上,正如本文所示,JUnit 和 FIT 互相补充。请把今年变成您追逐代码质量 的重要纪年 —— 由于决心采用 FIT!

上一页  [1] [2] [3] 

【责编:wayen】

中国IT教育

相关产品和培训
文章评论
 友情推荐链接
 认证培训
 专题推荐

 ·关于Java框架技术专题
 ·XML全攻略技术专题
 ·JAVA开源技术介绍专题
 ·Java嵌入式开发之J2ME技术专题
 ·超前体验 Oracle 11g的5个新特性…
 ·揭密使用VB.NET的五个实用技巧
 ·Oracle和SQL Server常用函数对比专题…
 ·展现C#世界 C#程序设计专题…
 ·Java入门 Tomcat的配置技巧精华专题…
 ·Oracle RMAN物理备份技术详解…
 今日更新
 社区讨论
 博客论点
 频道精选
 Java 频道导航