测试驱动开发-多币种实例3 笔记

14变化!

这里考虑的变化很简单:我们有两个法郎,想要换成一美元!

听起来就是一个测试用例:

@Test

   public voidtestReduceMoneyDifferentCurrency()

   {

      Bankbank = newBank();

      bank.addRate("CHF","USD",2);

      Moneyresult = bank.reduce(Money.Franc(2),"USD");

      assertEquals(Money.dollar(1),result);

     

   }

紧接上节课的结果,Bank类里面还没有addRate()方法。

可以通过添加先让编译通过。再来使它出现绿条。

Bank

 

public Money reduce(Expression source, String to) {

      return source.reduce(to);

   }

 

public voidaddRate(String currency, String to, int rate) {

  

   }

目前只是编译通过了。可以分析下,现在最快出现绿条的方法?

一段拙劣的代码来使测试通过。

Money

public Moneyreduce(String to) {

      int rate=(currency.equals("CHF")&&to.equals("USD"))?2:1;

      return new Money(amount/rate,to);

   }

可以看出,这段代码完全就是为了测试用例通过而写的。

汇率这个数据到底该由谁来确定呢?在现实生活中,当然是Bank

于是,这里就要修改代码,我们不得不将Bank作为一个参数传递给Expression.reduce()。因为只有Bank对象才能查出汇率的具体数值。

开始修改,首先是调用者:

Bank

public Money reduce(Expression source, String to) {

      return source.reduce(this,to);

   }

Bank对象调用了一个不存在的函数,根据报错继续修改。

然后是实现者:

Expression

Money reduce(Bank bank,String to);

MoneySum都做相同的修改。

这样修改完了之后,刚刚写在Money类中的那段拙劣的代码就可以移动到Bank类中了。

Bank

int rate(String from,String to)

   {

      return (from.equals("CHF")&&to.equals("USD"))?2:1;

   }

Money

public Money reduce(Bank bank,String to) {

      int rate=bank.rate(currency, to);

      return new Money(amount/rate,to);

   }

这时,这些类的关系已经比较有逻辑了。但是,还存在“坏味道”!

恼人的2~~~~~

为了除掉它,我们需要在Bank中保存一张汇率表,并且在需要时查找出相应的汇率。一张散列表(hash表)来将每对货币映射为汇率。

问题,我们可以使用一个包含两种货币的二元数组做为键值么?

Array.equals()会检查这些元素是否相等么?

这里需要一个小测试!

@Test

   public void testArrayEquals(){

      assertEquals(new Object[]{"abc"},new Object[]{"abc"});

   }

注意:书中说测试失败了。而我运行了一下是成功了。但是这种assertEquals已经不建议使用了。

接着按着书里的来

不得不创建一个真实的对象来作为键值。

public classPair {

 

   private String from;

   private String to;

   public Pair(String from,String to) {

      super();

      this.from = from;

      this.to = to;

   }

   @Override

   public int hashCode() {

      return 0;

   }

   @Override

   public boolean equals(Object obj) {

      Pairpair = (Pair) obj;

      return from.equals(pair.from)&&to.equals(pair.to);

   }

  

}

因为要把Pair作为键值,所以不得不实现equals()hashCode()

0是一个糟糕的散列值,但它容易实现,这时候货币查找就像是线性查找。

有了Pair类,就要在Bank中找个地方来存储汇率。

Bank

private Hashtable rates=newHashtable();

public voidaddRate(String from, String to, int rate) {

      rates.put(new Pair(from,to), new Integer(rate));

  

   }

在请求时查找汇率

int rate(String from,String to)

   {

      Integerrate=(Integer) rates.get(new Pair(from,to));

      return rate.intValue();

   }

注意:书上说,这里测试没通过。。可是,我又通过了。。。。

不过新增了一个测试

@Test

   public void testIdentityRate()

   {

      assertEquals(1,newBank().rate("USD","USD"));

   }

这个测试用例,一定不通过。因为没有向rates这个hashtable中存储一个这样的信息。但是,这个逻辑上有不用存储。所以继续改了一下rate(),如下

Bank

int rate(String from,String to)

   {

      if(from.equals(to))

      {

         return 1;

      }

      Integerrate=(Integer) rates.get(new Pair(from,to));

      return rate.intValue();

   }

 

15 混合货币

终于到了!!!混合货币的加法,测试用例

@Test

   public void testMixedAddition(){

      ExpressionfiveBucks = Money.dollar(5);

      ExpressiontenFrancs = Money.Franc(10);

      Bankbank = newBank();

      bank.addRate("CHF", "USD", 2);

      Moneyresult = bank.reduce(fiveBucks.plus(tenFrancs), "USD");

      assertEquals(Money.dollar(10),result);

   }

这是最符合需求的一个测试用例,但是很明显,作为Expression对象的fiveBucks并没有plus()这个函数实现。修改一出而牵连出其他错误是不明智的。那么就首先将Expression对象都改为Money对象。

 

 

之后运行测试,没有通过。得到15USD”,貌似追踪到Sum出现了问题,没有对传进来的参数进行化归。

Sum

public Money reduce(Bank bank,String to)

   {

      int amount = augend.reduce(bank, to).amount

                +addend.reduce(bank, to).amount;

      return new Money(amount ,to);

   }

测试通过了。下面就开始处理怎样将Money变量再换回Expression对象。

 

Sum

Expression augend;

   Expressionaddend;

   Sum(Expressionaugend,Expression addend)

   {

      this.augend=augend;

      this.addend=addend;

     

   }

Money

public Expression plus(Expression addend) {

      // TODO Auto-generated method stub

      return new Sum(this,addend);

   }

Expression times(int multiplier)

   {

      return new Money(amount*multiplier, currency);

   }

这里用到的一个写测试用例的方法,先从“叶子”再到“根”的方法来实施一般化(使用更抽象一些的声明)

 

16最后的工作。抽象

为了实现Expression.plus,我们需要实现Sum.plus(),接着需要实现Expression.times。继而整个例子就完成了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值