Test-driven development
61 of 133 
Expression
Expression  
Money reduce(Bank bank,
 String to)
;
Summ  
public
public Money reduce(Bank bank,
 String to) { 
int
int amount
=
 augend.amount 
+
 addend.amount
;
return
return nneww Money(amount
,
 to)
;
Money
Money  
public
public Money reduce(Bank bank,
 String to) { 
int
int rate 
=
 (currency.equals("CHF") & to.equals("USD")) 
? 2 
:
 1;
return
return nneww Money(amount / rate,
 to)
;
The methods have to be public because methods in interfaces have to be public (for 
some excellent reason, I’m sure.)   
Now we can calculate the rate in the Bank: 
Bank
Bank  
int
int rate(String from,
 String to) { 
return
return (from.equals("CHF") & to.equals("USD")) 
? 2 
:
 1;
And ask the bank for the right rate: 
Money
Money  
public
public Money reduce(Bank bank,
 String to) { 
int
int rate 
=
 bank.rate(currency,
 to)
;
return
return nneww Money(amount / rate,
 to)
;
That pesky “2” still appears in both the test and the code. To get rid of it, we need to 
keep a table of rates in the Bank and look up a rate when we need it. We could use a 
Hashtable mapping pairs of currencies to rates. Can we use a two element array 
containing the two currencies as the key? Does Array.equals() check to see if the 
elements are equal? 
public
public voidd test
ArrayEquals() { 
assertEquals(nneww Object[] {"abc"}
,
 neww Object[] {"abc"})
;
Nope. The test fails, so we have to create a real object for the key: 
Online pdf to tiff conversion - control SDK system:C# PDF Convert to Tiff SDK: Convert PDF to tiff images in C#.net, ASP.NET MVC, Ajax, WinForms, WPF
Online C# Tutorial for How to Convert PDF File to Tiff Image File
www.rasteredge.com
Online pdf to tiff conversion - control SDK system:VB.NET PDF Convert to Tiff SDK: Convert PDF to tiff images in vb.net, ASP.NET MVC, Ajax, WinForms, WPF
Free VB.NET Guide to Render and Convert PDF Document to TIFF
www.rasteredge.com
Test-driven development
62 of 133 
Pair
Pair  
private class Pair { 
private String from;
private String to;
Pair(String from,
 String to) { 
this.
from=
 from;
this.
to=
 to;
Because we are using Pairs as keys, we have to implement equals() and hashCode(). 
I’m not going to wr ite tests for these, because we are writing this code in the context 
of a refactoring. If we get to the payoff of the refactoring and all the tests run, we 
expect the code to have been exercised. If I was programming with someone who 
didn’t see exactly whe re we were going with this, or if the logic became the least bit 
complex, I would begin writing separate tests. 
Pair
Pair  
public
public boolean
boolean equals(Object object) { 
Pair pair=
 (Pair) object
;
return
return from.equals(pair.
from) & to.equals(pair.
to)
;
publi
publicc 
int
int hashCode() { 
return
return 0
;
“0” is a terrible hash value, but it has the advantage that it’s easy to implement and it 
will get us running quickly. Currency lookup will look like linear search. When we get 
lots of currencies, we can do a more thorough job with real usage data. 
We need somewhere to store the rates: 
Bank
Bank  
private
private Hashtable rates=
 neww Hashtable()
;
We need to set the rate when told: 
Bank
Bank  
void
void addRate(String from,
 String to,
int
int rate) { 
rates.put(neww Pair(from,
 to)
,
 nneeww Integer(rate))
;
And then we can look up the rate when asked: 
control SDK system:Online Convert PDF file to Tiff. Best free online PDF Tif
Online PDF to Tiff Converter. Download Free Trial. Then just wait until the conversion from PDF to Tiff is complete and download the file.
www.rasteredge.com
control SDK system:Online Convert PDF file to Word. Best free online PDF Conversion
Online Tiff to PDF Converter. Convert a Tiff/Tif File to PDF. Just upload your file by clicking on the blue button or drag-and-drop your Tiff or Tif file into
www.rasteredge.com
Test-driven development
63 of 133 
Bank
Bank  
int
int rate(String from,
 String to) { 
Integer rate=
 (Integer) rates.get(nneww Pair(from,
 to))
;
return
return rate.intValue()
;
Wait a minute!? We got a red bar. What happened? A little snooping around tells us 
that if we ask for the rate from USD to USD, we expect the value to be 1. Since this 
was a surprise, let’s write a test to communicate what we discovered:  
public
public voidd testIdent
i
tyRate() { 
assertEquals(1,
 neww Bank()
.rate("USD",
 "USD"))
;
Now we have three errors, but we expect them all to be fixed with one change: 
Bank
Bank  
int
int rate(String from,
 String to) { 
iff (from.equals(to)) return
return 1;
Integer rate=
 (Integer) rates.get(nneww Pair(from,
 to))
;
return
return rate.intValue()
;
Green bar! 
T
o do
:
$5 + 
10
CHF = $
10
i
f CHF
:
USD 
is
2
:1
$5 + $5 = $
10
Re
t
urn Money from $5 + $5 
Bank.reduce(Money)
Reduce Money 
wit
h con
v
er
si
on
Reduce(Bank, S
t
r
i
ng) 
vs
reduce(S
t
r
i
ng) 
Next we’ll implement our last big test, $5 + 10 CHF. Several significant techniques 
have slipped into this chapter: 
·  Added a parameter, in seconds, that we expected we would need 
·  Factored out the data duplication between code and tests 
·  Wrote a test (testArrayEquals) to check an assumption about the operation of 
Java 
·  Introduced a private helper class without distinct tests of its own 
·  Made a mistake in a refactoring and chose to forge ahead, writing another test 
to isolate the problem 
control SDK system:Online Convert Excel to PDF file. Best free online export xlsx
Online Excel to PDF Converter. Download Free Trial. Your file will then be instantly converted to PDF and ready to download. The perfect conversion tool.
www.rasteredge.com
control SDK system:.NET PDF Document Viewing, Annotation, Conversion & Processing
In addition, .NET programming examples for all these functions are provided online. Convert PDF to Word (.docx). Convert PDF to images, like Tiff.
www.rasteredge.com
Test-driven development
64 of 133 
Mixed Currencies 
Now we are finally ready to add the test that started it all, $5 + 10 CHF: 
public
public voidd testMixedAddi
t
ion() { 
Expression fiveBucks=
 Money.dollar(5)
;
Expression tenFrancs=
 Money.
franc(10)
;
Bank bank=
 neww Bank()
;
bank.addRate("CHF",
 "USD",
 2)
;
Money resul
t
=
 bank.reduce(fiveBucks.plus(tenFrancs)
,
 "USD")
;
assertEquals(Money.dollar(10)
,
 resul
t)
;
This is what we’d like to write. Unfortunately, there are a host of compile errors. 
When we were generalizing from Money to Expression, we left a lot of loose ends 
laying around. I was worried about them, but I didn’t want to disturb you. It’s 
disturbing time, now. 
We won’t be able to get the test above to compile quickly. We will make the first 
change that will ripple to the next and the next. We have two paths forward. We can 
make it work quickly by writing a more specific test and then generalizing, or we can 
trust our compiler not to let us make mistakes. I’m with you — — let’s go slow (in 
practice I would probably just fix the rippling changes one at a time). 
public
public voidd testMixedAddi
t
ion() { 
Money
Money fiveBucks=
 Money.dollar(5)
;
Money
Money tenFrancs=
 Money.
franc(10)
;
Bank bank=
 neww Bank()
;
bank.addRate("CHF",
 "USD",
 2)
;
Money resul
t
=
 bank.reduce(fiveBucks.plus(tenFrancs)
,
 "USD")
;
assertEquals(Money.dollar(10)
,
 resul
t)
;
The test doesn’t work. We get 15 USD instead of 10 USD. It’s as if Sum.reduce() isn’t 
reducing the arguments. It isn’t:  
Summ  
public
public Money reduce(Bank bank,
 String to) { 
int
int amount
=
 augend.amount 
+
 addend.amount
;
return
return nneww Money(amount
,
 to)
;
If we reduce both of the arguments, the test should pass: 
control SDK system:C# Create PDF from Tiff Library to convert tif images to PDF in C#
Online demo allows converting tiff to PDF online. C# source codes are provided to use in .NET class. In addition to PDF to Tiff conversion, our .NET PDF
www.rasteredge.com
control SDK system:VB.NET Create PDF from Tiff Library to convert tif images to PDF
online. Source codes are provided to use in VB.NET class. Free library and components for downloading and using in .NET framework. Except PDF to Tiff conversion
www.rasteredge.com
Test-driven development
65 of 133 
Summ  
public
public Money reduce(Bank bank,
 String to) { 
int
int amount
=
 augend.reduce(bank,
 to)
reduce(bank,
 to)
.amount 
+
 addend.reduce(bank,
reduce(bank,
to))
.amount
;
return
return nneww Money(amount
,
 to)
;
And it does. Now we can begin pecking away at Moneys that should be Expressions. 
To avoid the ripple effect, we’ll start at the edges  and work our way back to the test 
case. For example, the augend and addend can now be Expressions: 
Summ  
Expression
Expression augend;
Expression
Expression addend;
The arguments to the Sum constructor can also be Expressions: 
Summ  
Sum(Expression
Expression augend,
 Expression
Expression addend) { 
thiiss.augend=
 augend;
thiiss.addend=
 addend;
(Sum is starting to remind me of Composite, but not so much that I want to generalize. 
The moment we want a Sum with other than two parameters, though, I’m ready to 
transform it.) So much for Sum. How about Money? 
The argument to plus() can be an Expression: 
Money
Money  
Expression
Expression plus(Expression
Expression addend) { 
return
return nneww Sum(thhiiss,
 addend)
;
Times() can return an Expression: 
Money
Money  
Expression
Expression t
imes(
int
int mul
t
iplier) { 
return
return nneww Money(amount * mul
t
iplier,
 currency)
;
This suggests that Expression should include the operations plus() and times(). That’s 
all for Money. We can now change the argument to plus() in our test case: 
control SDK system:C# TIFF: C#.NET Code to Convert TIFF Image File
Online C# tutorial for high-fidelity Tiff image file conversion from MS Office Word, Excel, and PowerPoint document. Convert PDF to Tiff Using C#.
www.rasteredge.com
control SDK system:VB.NET PDF Converter Library SDK to convert PDF to other file
plug-in embeds several image compression mechanisms, it can be used for multiple PDF to image converting applications, like PDF to tiff conversion, PDF to JPEG
www.rasteredge.com
Test-driven development
66 of 133 
public
public voidd testMixedAddi
t
ion() { 
Money fiveBucks=
 Money.dollar(5)
;
Expression
Expression tenFrancs=
 Money.
franc(10)
;
Bank bank=
 neww Bank()
;
bank.addRate("CHF",
 "USD",
 2)
;
Money resul
t
=
 bank.reduce(fiveBucks.plus(tenFrancs)
,
 "USD")
;
assertEquals(Money.dollar(10)
,
 resul
t)
;
When we change fiveBucks to an Expression, we have to make several changes. 
Fortunately we have the compiler’s to -do list to keep us focused. First we make the 
change: 
public
public voidd testMixedAddi
t
ion() { 
Expression
Expression fiveBucks=
 Money.dollar(5)
;
Expression tenFrancs=
 Money.
franc(10)
;
Bank bank=
 neww Bank()
;
bank.addRate("CHF",
 "USD",
 2)
;
Money resul
t
=
 bank.reduce(fiveBucks.plus(tenFrancs)
,
 "USD")
;
assertEquals(Money.dollar(10)
,
 resul
t)
;
We are politely told that plus() is not defined for Expressions. We define it: 
Expression
Expression  
Expression plus(Expression addend)
;
And then we have to add it to Money and Sum. Money? Yes, it has to be public in 
Money: 
Money
Money  
public
public Expression plus(Expression addend) { 
return
return nneww Sum(thhiiss,
 addend)
;
We’ll just stub out the implementation in Sum, and add it to our list:  
Summ  
public
public Expression plus(Expression addend) { 
return
return null
null;
Now that the program compiles, the tests all run. 
T
o do
:
$5 + 
10
CHF = $
10
i
f CHF
:
USD 
is
2
:1
$5 + $5 = $
10
Re
t
urn Money from $5 + $5 
Bank.reduce(Money)
Reduce Money 
wit
h con
v
er
si
on
Reduce(Bank, S
t
r
i
ng) 
vs
reduce(E
x
pre
ssi
on, S
t
r
i
ng) 
E
x
pre
ssi
on.p
l
u
s
Sum.p
l
u
s
E
x
pre
ssi
on.
ti
me
s
We are ready to finish generalizing Money to Expression, but first we’ll review. We:  
control SDK system:XDoc.Converter for .NET, Support Documents and Images Conversion
Convert Adobe PDF to image. Convert Tiff to image. Convert Word, Excel and PDF to image. Next Steps. Download and try Converter for .NET with online support.
www.rasteredge.com
Test-driven development
67 of 133 
·  Wrote the test we wanted, then backed off to make it achievable in one step 
·  Generalized (used a more abstract declaration) from the leaves back to the root 
(the test case) 
·  Followed the compiler when we made a change (Expression fiveBucks) which 
caused changes to ripple (added plus() to Expression, etc.) 
Test-driven development
68 of 133 
Abstraction, Finally 
We need to implement Sum.plus() to finish Expression.plus, and then we need 
Expression.times(), and then we’re finished with the whole example. Here’s the test 
for Sum.plus(): 
public
public voidd testSumPlusMoney() { 
Expression fiveBucks=
 Money.dollar(5)
;
Expression tenFrancs=
 Money.
franc(10)
;
Bank bank=
 neww Bank()
;
bank.addRate("CHF",
 "USD",
 2)
;
Expression sum=
 neww Sum(fiveBucks,
 tenFrancs)
.plus(fiveBucks)
;
Money resul
t
=
 bank.reduce(sum,
 "USD")
;
assertEquals(Money.dollar(15)
,
 resul
t)
;
We could have created a Sum by adding fiveBucks and tenFrancs, but the form above, 
where we explicitly create the Sum, communicates more directly. You are writing 
these tests not just to make your experience of programming more fun and rewarding, 
but also as a Rosetta Stone for future generations to appreciate your genius. Think, oh 
think, of your readers. 
The test, in this case, is longer than the code. The code is the same as the code in 
Money (do I hear an abstract class in the distance?): 
Summ  
public
public Expression plus(Expression addend) { 
return
return nneww Sum(thhiiss,
 addend)
;
You will likely end up with about the same number of lines of test code as model code 
when TDDing. For TDD to make economic sense, either you will have to be able to 
write twice as many lines per day as before, or write half as many lines for the same 
functionality. You’ll have to measure and see what effect TDD has on your own 
practice. Be sure to factor debugging, integrating, and explaining time into your 
metrics, though. 
If we can make Sum.times() work, then declaring Expression.times() will be one 
simple step. The test is: 
Test-driven development
69 of 133 
public
public voidd testSumTimes() { 
Expression fiveBucks=
 Money.dollar(5)
;
Expression tenFrancs=
 Money.
franc(10)
;
Bank bank=
 neww Bank()
;
bank.addRate("CHF",
 "USD",
 2)
;
Expression sum=
 neww Sum(fiveBucks,
 tenFrancs)
.
t
imes(2)
;
Money resul
t
=
 bank.reduce(sum,
 "USD")
;
assertEquals(Money.dollar(20)
,
 resul
t)
;
Again, the test is longer than the code (you JUnit geeks will know how to fix that— the 
rest of you will have to read Fixture): 
Summ  
Expression t
imes(
int
int mul
t
iplier) { 
return
return nneww Sum(augend.
t
imes(mul
t
iplier)
,
 addend.
t
imes(mul
t
iplier))
;
Since we abstracted augend and addend to Expressions in the last chapter, we now 
have to declare times() in Expression before the code will compile: 
Expression
Expression  
Expression t
imes(
int
int mul
t
iplier)
;
Which forces us to raise the visibility of Money.times() and Sum.times(): 
Summ  
public
public Expression t
imes(
int
int mul
t
iplier) { 
return
return nneww Sum(augend.
t
imes(mul
t
iplier)
,
 addend.
t
imes(mul
t
iplier))
;
Money
Money  
public
public Expression t
imes(
iintt mul
t
iplier) { 
return
return nneww Money(amount * mul
t
iplier,
 currency)
;
And it works. 
T
o do
:
$5 + 
10
CHF = $
10
i
f CHF
:
USD 
is
2
:1
$5 + $5 = $
10
Re
t
urn Money from $5 + $5 
Bank.reduce(Money)
Reduce Money 
wit
h con
v
er
si
on
Reduce(Bank, S
t
r
i
ng) 
vs
reduce(E
x
pre
ssi
on, S
t
r
i
ng) 
E
x
pre
ssi
on.p
l
u
s
Sum.p
l
u
s
E
x
pre
ssi
on.
ti
me
s
The only loose end to tie up is to experiment with returning a Money when we add $5 
+ $5. The test would be: 
Test-driven development
70 of 133 
public
public voidd testPlusSameCurrencyReturnsMoney() { 
Expression sum=
 Money.dollar(1)
.plus(Money.dollar(1))
;
assert
True(sum 
instanceof
instanceof Money)
;
This test is a little ugly, because it is testing the guts of the implementation, not the 
externally visible behavior of the objects. However, it will drive us to make the 
changes we need to make, and this is only an experiment, after all. Here is the code we 
would have to modify to make it work: 
Money
Money  
public
public Expression plus(Expression addend) { 
return
return nneww Sum(thhiiss,
 addend)
;
There is no obvious, clean way (not to me, anyway, I’m sure you could think  of 
something) to check the currency of the argument if and only if it is a Money. The 
experiment fails, we delete the test (which we didn’t like much anyway), and away we 
go. 
T
o do
:
$5 + 
10
CHF = $
10
i
f CHF
:
USD 
is
2
:1
$5 + $5 = $
10
Re
t
urn Money from $5 + 
$5
Bank.reduce(Money)
Reduce Money 
wit
h con
v
er
si
on
Reduce(Bank, S
t
r
i
ng) 
vs
reduce(E
x
pre
ssi
on, S
t
r
i
ng) 
E
x
pre
ssi
on.p
l
u
s
Sum.p
l
u
s
E
x
pre
ssi
on.
ti
me
s
The final item on the list, finding a better name for the helper method for 
Bank.reduce(), still isn’t obvious.  Our design can only reflect our understanding. Less 
than perfect understanding implies a less than perfect design, and there is no such 
thing as perfect understanding. We still have to ship. A moment of silence, then, for 
our less than perfect design… Than k you. Now ship it. 
T
o do
:
$5 + 
10
CHF = $
10
i
f CHF
:
USD 
is
2
:1
$5 + $5 = $
10
Re
t
urn Money from $5 + $5
Bank.reduce(Money)
Reduce Money 
wit
h con
v
er
si
on
Reduce(Bank, S
t
r
i
ng) 
vs
reduce(E
x
pre
ssi
on, S
t
r
i
ng)
E
x
pre
ssi
on.p
l
u
s
Sum.p
l
u
s
E
x
pre
ssi
on.
ti
me
s
Reviewing, we: 
·  Wrote a test with future readers in mind 
·  Suggested an experiment comparing TDD with your current programming 
style 
Documents you may be interested
Documents you may be interested