您的位置:首页 > 其它

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

2012-12-18 00:56 405 查看
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);

Money和Sum都做相同的修改。

这样修改完了之后,刚刚写在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对象。

之后运行测试,没有通过。得到15“USD”,貌似追踪到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。继而整个例子就完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: