File: testing.htm

package info (click to toggle)
junit 3.8.2-9
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster, sid
  • size: 1,704 kB
  • sloc: java: 1,762; sh: 43; makefile: 34; xml: 26
file content (616 lines) | stat: -rw-r--r-- 31,432 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
   <meta name="GENERATOR" content="Mozilla/4.75 [en] (Windows NT 5.0; U) [Netscape]">
   <title>Test Infected: </title>
</head>
<body>

<h1>
<b><font color="#00CC00">J</font><font color="#FF0000">U</font><font color="#000000">nit</font> <font size=+3>Test
Infected: Programmers Love Writing Tests</font></b></h1>

<hr WIDTH="100%">
<p>Testing is not closely integrated with development. This prevents you
from measuring the progress of development- you can't tell when something
starts working or when something stops working. Using <i>JUnit</i> you
can cheaply and incrementally build a test suite that will help you measure
your progress, spot unintended side effects, and focus your development
efforts.
<h1>
Contents</h1>

<ul>
<li>
<a href="#TheProblem">The Problem</a></li>

<li>
<a href="#Example">Example</a></li>

<li>
<a href="#TestingPractices">Testing Practices</a></li>

<li>
<a href="#Conclusion">Conclusions</a></li>
</ul>

<h1>
<a NAME="TheProblem"></a>The Problem</h1>
Every programmer knows they should write tests for their code. Few do.
The universal response to "Why not?" is "I'm in too much of a hurry." This
quickly becomes a vicious cycle- the more pressure you feel, the fewer
tests you write. The fewer tests you write, the less productive you are
and the less stable your code becomes. The less productive and accurate
you are, the more pressure you feel.
<p>Programmers burn out from just such cycles. Breaking out requires an
outside influence. We found the outside influence we needed in a simple
testing framework that lets us do a little testing that makes a big difference.
<p>The best way to convince you of the value of writing your own tests
would be to sit down with you and do a bit of development. Along the way,
we would encounter new bugs, catch them with tests, fix them, have them
come back, fix them again, and so on. You would see the value of the immediate
feedback you get from writing and saving and rerunning your own unit tests.
<p>Unfortunately, this is an article, not an office overlooking charming
old-town Z&uuml;rich, with the bustle of medieval commerce outside and
the thump of techno from the record store downstairs, so we'll have to
simulate the process of development. We'll write a simple program and its
tests, and show you the results of running the tests. This way you can
get a feel for the process we use and advocate without having to pay for
our presence.
<h1>
<a NAME="Example"></a>Example</h1>
As you read, pay attention to the interplay of the code and the tests.
The style here is to write a few lines of code, then a test that should
run, or even better, to write a test that won't run, then write the code
that will make it run.
<p>The program we write will solve the problem of representing arithmetic
with multiple currencies. Arithmetic between single currencies is trivial,
you can just add the two amounts. Simple numbers suffice. You can ignore
the presence of currencies altogether.
<p>Things get more interesting once multiple currencies are involved. You
cannot just convert one currency into another for doing arithmetic since
there is no single conversion rate- you may need to compare the value of
a portfolio at yesterday's rate and today's rate.
<p>Let's start simple and define a class <a href="#classMoney">Money</a>
to represent a value in a single currency. We represent the amount by a
simple int. To get full accuracy you would probably use double or java.math.BigDecimal
to store arbitrary-precision signed decimal numbers. We represent a currency
as a string holding the ISO three letter abbreviation (USD, CHF, etc.).
In more complex implementations, currency might deserve its own object.
<pre><a NAME="classMoney"></a><tt>class Money {
&nbsp;&nbsp;&nbsp; private int fAmount;
&nbsp;&nbsp;&nbsp; private String fCurrency;</tt></pre>

<pre><tt>&nbsp;&nbsp;&nbsp; public Money(int amount, String currency) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fAmount= amount;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fCurrency= currency;
&nbsp;&nbsp;&nbsp; }

&nbsp;&nbsp;&nbsp; public int amount() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fAmount;
&nbsp;&nbsp;&nbsp; }

&nbsp;&nbsp;&nbsp; public String currency() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return fCurrency;
&nbsp;&nbsp;&nbsp; }
}</tt></pre>
When<font size=-1> </font>you add two Moneys of the same currency, the
resulting Money has as its amount the sum of the other two amounts.
<pre><a NAME="MoneyAdd"></a><tt>public Money add(Money m) {
&nbsp;&nbsp;&nbsp; return new Money(amount()+m.amount(), currency());
}</tt></pre>
Now, instead of just coding on, we want to get immediate feedback and practice
"code a little, test a little, code a little, test a little". To implement
our tests we use the JUnit framework. To write tests you need to get the
<a href="http://sourceforge.net/projects/junit/">latest
copy</a> JUnit (or write your own equivalent- it's not so much work).
<p>JUnit defines how to structure your test cases and provides the tools
to run them. You implement a test in a subclass of TestCase. To test our
Money implementation we therefore define <a href="#class MoneyTest">MoneyTest</a>
as a subclass of TestCase. In Java, classes are contained in packages and
we have to decide where to put MoneyTest. Our current practice is to put
MoneyTest in the same package as the classes under test. In this way a
test case has access to the package private methods. We add a test method
testSimpleAdd, that will exercise the simple version of <a href="#MoneyAdd">Money.add()</a>
above. A JUnit test method is an ordinary method without any parameters.
<pre><a NAME="class MoneyTest"></a><tt>public class MoneyTest extends TestCase {
&nbsp;&nbsp;&nbsp; //
&nbsp;&nbsp;&nbsp; public void testSimpleAdd() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money m12CHF= new Money(12, "CHF");&nbsp; //&nbsp;<a NAME="MoneyTest1"></a>(1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money m14CHF= new Money(14, "CHF");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money expected= new Money(26, "CHF");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money result= m12CHF.add(m14CHF);&nbsp;&nbsp;&nbsp; //&nbsp;<a NAME="MoneyTest2"></a>(2)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Assert.assertTrue(expected.equals(result));&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;<a NAME="MoneyTest3"></a>(3)
&nbsp;&nbsp;&nbsp; }
}</tt></pre>
The testSimpleAdd() test case consists of:
<ol>
<li>
<a href="#MoneyTest1">Code</a> which creates the objects we will interact
with during the test. This testing context is commonly referred to as a
test's<i> fixture</i>. All we need for the testSimpleAdd test are some
Money objects.</li>

<li>
<a href="#MoneyTest2">Code</a> which exercises the objects in the fixture.</li>

<li>
<a href="#MoneyTest3">Code</a> which verifies the result.</li>
</ol>
Before we can verify the result we have to digress a little since we need
a way to test that two Money objects are equal. The Java idiom to do so
is to override the method <i>equals</i> defined in Object. Before we implement
equals let's a write a test for equals in MoneyTest.
<pre><tt>public void testEquals() {
&nbsp;&nbsp;&nbsp; Money m12CHF= new Money(12, "CHF");
&nbsp;&nbsp;&nbsp; Money m14CHF= new Money(14, "CHF");

&nbsp;&nbsp;&nbsp; Assert.assertTrue(!m12CHF.equals(null));
&nbsp;&nbsp;&nbsp; Assert.assertEquals(m12CHF, m12CHF);
&nbsp;&nbsp;&nbsp; Assert.assertEquals(m12CHF, new Money(12, "CHF")); //&nbsp;<a NAME="TestEquals1"></a>(1)
&nbsp;&nbsp;&nbsp; Assert.assertTrue(!m12CHF.equals(m14CHF));
}</tt></pre>
The equals method in Object returns true when both objects are the same.
However, Money is a <i>value object</i>. Two Monies are considered equal
if they have the same currency and value. To test this property we have
added a test <a href="#TestEquals1">(1)</a> to verify that Monies are equal
when they have the same value but are not the same object.
<p>Next let's write the equals method in Money:
<pre><tt>public boolean equals(Object anObject) {
&nbsp;&nbsp;&nbsp; if (anObject instanceof Money) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Money aMoney= (Money)anObject;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return aMoney.currency().equals(currency())
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; amount() == aMoney.amount();
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; return false;
}</tt></pre>
Since equals can receive any kind of object as its argument we first have
to check its type before we cast it as a Money. As an aside, it is a recommended
practice to also override the method hashCode whenever you override method
equals. However, we want to get back to our test case.
<p>With an equals method in hand we can verify the outcome of testSimpleAdd.
In JUnit you do so by a calling
<A HREF="../../javadoc/junit/framework/Assert.html#assertTrue(boolean)">Assert.assertTrue</a>,
which triggers a failure that is recorded by JUnit when the argument isn't
true. Since assertions for equality are very common, there is also
an Assert.assertEquals convenience method. In addition to testing for equality
with equals, it reports the printed value of the two objects in the case they
differ. This lets us immediately see why a test failed in a JUnit test
result report. The value a string representation created by
the toString converter method.
There are <a href="../../javadoc/junit/framework/Assert.html">
other asertXXXX variants</a> not discussed here.
<p>Now that we have implemented two test cases we notice some code duplication
for setting-up the tests. It would be nice to reuse some of this test set-up
code. In other words, we would like to have a common fixture for running
the tests. With JUnit you can do so by storing the fixture's objects in
instance variables of your
<a href="../../javadoc/junit/framework/TestCase.html">TestCase</a>
subclass and initialize them by overridding
the setUp method. The symmetric operation to setUp is tearDown which you
can override to clean up the test fixture at the end of a test. Each test
runs in its own fixture and JUnit calls setUp and tearDown for each test
so that there can be no side effects among test runs.
<pre><tt>public class MoneyTest extends TestCase {
&nbsp;&nbsp;&nbsp; private Money f12CHF;
&nbsp;&nbsp;&nbsp; private Money f14CHF;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp; protected void setUp() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f12CHF= new Money(12, "CHF");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f14CHF= new Money(14, "CHF");
&nbsp;&nbsp;&nbsp; }
}</tt></pre>
We can rewrite the two test case methods, removing the common setup code:
<pre><tt>public void testEquals() {
&nbsp;&nbsp;&nbsp; Assert.assertTrue(!f12CHF.equals(null));
&nbsp;&nbsp;&nbsp; Assert.assertEquals(f12CHF, f12CHF);
&nbsp;&nbsp;&nbsp; Assert.assertEquals(f12CHF, new Money(12, "CHF"));
&nbsp;&nbsp;&nbsp; Assert.assertTrue(!f12CHF.equals(f14CHF));
}

public void testSimpleAdd() {
&nbsp;&nbsp;&nbsp; Money expected= new Money(26, "CHF");
&nbsp;&nbsp;&nbsp; Money result= f12CHF.add(f14CHF);
&nbsp;&nbsp;&nbsp; Assert.assertTrue(expected.equals(result));
}</tt></pre>
Two additional steps are needed to run the two test cases:
<ol>
<li>
define how to run an individual test case,</li>

<li>
define how to run a <i>test suite</i>.</li>
</ol>
JUnit supports two ways of running single tests:
<ul>
<li>
static</li>

<li>
dynamic</li>
</ul>
In the static way you override the runTest method inherited from TestCase
and call the desired test case. A convenient way to do this is with an
anonymous inner class. Note that each test must be given a name, so you
can identify it if it fails.
<pre><tt>TestCase test= new MoneyTest("simple add") {
&nbsp;&nbsp;&nbsp; public void runTest() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; testSimpleAdd();
&nbsp;&nbsp;&nbsp; }
};</tt></pre>
A template method<a href="#Gamma, E., et al. Design Patterns: Elements of">[1]</a>
in the superclass will make sure runTest is executed when the time comes.
<p>The dynamic way to create a test case to be run uses reflection to implement
runTest. It assumes the name of the test is the name of the test case method
to invoke. It dynamically finds and invokes the test method. To invoke
the testSimpleAdd test we therefore construct a MoneyTest as shown below:
<pre><tt>TestCase test= new MoneyTest("testSimpleAdd");</tt></pre>
The dynamic way is more compact to write but it is less static type safe.
An error in the name of the test case goes unnoticed until you run it and
get a NoSuchMethodException. Since both approaches have advantages, we
decided to leave the choice of which to use up to you.
<p>As the last step to getting both test cases to run together, we have
to define a test suite. In JUnit this requires the definition of a static
method called suite. The suite method is like a main method that is specialized
to run tests. Inside suite you add the tests to be run to a
<a href="../../javadoc/junit/framework/TestSuite.html">TestSuite</a> object
and return it. A TestSuite can run a collection of tests. TestSuite and
TestCase both implement an interface called Test which defines the methods
to run a test. This enables the creation of test suites by composing arbitrary
TestCases and TestSuites. In short TestSuite is a Composite <a href="#Gamma, E., et al. Design Patterns: Elements of">[1].</a>
The code below illustrates the creation of a test suite with the dynamic
way to run a test.
<pre><tt>public static Test suite() {
&nbsp;&nbsp;&nbsp; TestSuite suite= new TestSuite();
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testEquals"));
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testSimpleAdd"));
&nbsp;&nbsp;&nbsp; return suite;
}</tt></pre>
Since JUnit 2.0 there is an even simpler dynamic way. You only pass the
class with the tests to a TestSuite and it extracts the test methods automatically.
<p><tt>public static Test suite() {<br>
&nbsp;&nbsp;&nbsp; return new TestSuite(MoneyTest.class);<br>
}</tt><tt></tt>
<p>Here is the corresponding code using the static way.
<pre><tt>public static Test suite() {
&nbsp;&nbsp;&nbsp; TestSuite suite= new TestSuite();
&nbsp;&nbsp;&nbsp; suite.addTest(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new MoneyTest("money equals") {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void runTest() { testEquals(); }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; );
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; suite.addTest(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new MoneyTest("simple add") {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void runTest() { testSimpleAdd(); }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; );
&nbsp;&nbsp;&nbsp; return suite;
}</tt></pre>
Now we are ready to run our tests. JUnit comes with a graphical&nbsp; interface
to run tests. Type the name of your test class in the field at the top
of the window. Press the Run button. While the test is run JUnit shows
its progress with a progress bar below the input field. The bar is initially
green but turns into red as soon as there is an unsuccessful test. Failed
tests are shown in a list at the bottom. <a href="#Figure1">Figure 1</a>
shows the TestRunner window after we run our trivial test suite.
<center><img SRC="IMG00001.GIF" >
<br><a NAME="Figure1"></a><b>Figure 1</b>: A Successful Run</center>

<p>After having verified that the simple currency case works we move on
to multiple currencies. As mentioned above the problem of mixed currency
arithmetic is that there isn't a single exchange rate. To avoid this problem
we introduce a MoneyBag which defers exchange rate conversions. For example
adding 12 Swiss Francs to 14 US Dollars is represented as a bag containing
the two Monies 12 CHF and 14 USD. Adding another 10 Swiss francs gives
a bag with 22 CHF and 14 USD. We can later evaluate a MoneyBag with different
exchange rates.
<p>A MoneyBag is represented as a list of Monies and provides different
constructors to create a MoneyBag. Note, that the constructors are package
private since MoneyBags are created behind the scenes when doing currency
arithmetic.
<pre><tt>class MoneyBag {
&nbsp;&nbsp;&nbsp; private Vector fMonies= new Vector();

&nbsp;&nbsp;&nbsp; MoneyBag(Money m1, Money m2) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appendMoney(m1);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appendMoney(m2);
&nbsp;&nbsp;&nbsp; }

&nbsp;&nbsp;&nbsp; MoneyBag(Money bag[]) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i= 0; i &lt; bag.length; i++)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appendMoney(bag[i]);
&nbsp;&nbsp;&nbsp; }
}</tt></pre>
The method appendMoney is an internal helper method that adds a Money to
the list of Moneys and takes care of consolidating Monies with the same
currency. MoneyBag also needs an equals method together with a corresponding
test. We skip the implementation of equals and only show the testBagEquals
method. In a first step we extend the fixture to include two MoneyBags.
<pre><tt>protected void setUp() {
&nbsp;&nbsp;&nbsp; f12CHF= new Money(12, "CHF");
&nbsp;&nbsp;&nbsp; f14CHF= new Money(14, "CHF");
&nbsp;&nbsp;&nbsp; f7USD=&nbsp; new Money( 7, "USD");
&nbsp;&nbsp;&nbsp; f21USD= new Money(21, "USD");
&nbsp;&nbsp;&nbsp; fMB1= new MoneyBag(f12CHF, f7USD);
&nbsp;&nbsp;&nbsp; fMB2= new MoneyBag(f14CHF, f21USD);
}</tt></pre>
With this fixture the testBagEquals test case becomes:
<pre><tt>public void testBagEquals() {
&nbsp;&nbsp;&nbsp; Assert.assertTrue(!fMB1.equals(null));
&nbsp;&nbsp;&nbsp; Assert.assertEquals(fMB1, fMB1);
&nbsp;&nbsp;&nbsp; Assert.assertTrue(!fMB1.equals(f12CHF));
&nbsp;&nbsp;&nbsp; Assert.assertTrue(!f12CHF.equals(fMB1));
&nbsp;&nbsp;&nbsp; Assert.assertTrue(!fMB1.equals(fMB2));
}</tt></pre>
Following "code a little, test a little" we run our extended test with
JUnit and verify that we are still doing fine. With MoneyBag in hand, we
can now fix the add method in Money.
<pre><tt>public Money add(Money m) {
&nbsp;&nbsp;&nbsp; if (m.currency().equals(currency()) )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new Money(amount()+m.amount(), currency());
&nbsp;&nbsp;&nbsp; return new MoneyBag(this, m);
}</tt></pre>
As defined above this method will not compile since it expects a Money
and not a MoneyBag as its return value. With the introduction of MoneyBag
there are now two representations for Moneys which we would like to hide
from the client code. To do so we introduce an interface IMoney that both
representations implement. Here is the IMoney interface:
<pre><tt>interface IMoney {
&nbsp;&nbsp;&nbsp; public abstract IMoney add(IMoney aMoney);
&nbsp;&nbsp;&nbsp; //
}</tt></pre>
To fully hide the different representations from the client we have to
support arithmetic between all combinations of Moneys with MoneyBags. Before
we code on, we therefore define a couple more test cases. The expected
MoneyBag results use the convenience constructor shown above, initializing
a MoneyBag from an array.
<pre><tt>public void testMixedSimpleAdd() {&nbsp;
&nbsp;&nbsp;&nbsp; // [12 CHF] + [7 USD] == {[12 CHF][7 USD]}&nbsp;
&nbsp;&nbsp;&nbsp; Money bag[]= { f12CHF, f7USD };&nbsp;
&nbsp;&nbsp;&nbsp; MoneyBag expected= new MoneyBag(bag);&nbsp;
&nbsp;&nbsp;&nbsp; Assert.assertEquals(expected, f12CHF.add(f7USD));&nbsp;
}</tt></pre>
The other tests follow the same pattern:
<menu>
<li>
testBagSimpleAdd - to add a MoneyBag to a simple Money</li>

<li>
testSimpleBagAdd - to add a simple Money to a MoneyBag</li>

<li>
testBagBagAdd - to add two MoneyBags</li>
</menu>
Next, we extend our test suite accordingly:
<pre><tt>public static Test suite() {
&nbsp;&nbsp;&nbsp; TestSuite suite= new TestSuite();
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testMoneyEquals"));
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testBagEquals"));
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testSimpleAdd"));
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testMixedSimpleAdd"));
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testBagSimpleAdd"));
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testSimpleBagAdd"));
&nbsp;&nbsp;&nbsp; suite.addTest(new MoneyTest("testBagBagAdd"));
&nbsp;&nbsp;&nbsp; return suite;
}</tt></pre>
Having defined the test cases we can start to implement them. The implementation
challenge here is dealing with all the different combinations of Money
with MoneyBag. Double dispatch <a href="#Beck, K. Smalltalk Best Practice Patterns,">[2]</a>
is an elegant way to solve this problem. The idea behind double dispatch
is to use an additional call to discover the kind of argument we are dealing
with. We call a method on the argument with the name of the original method
followed by the class name of the receiver. The add method in Money and
MoneyBag becomes:
<pre><tt>class Money implements IMoney {
&nbsp;&nbsp;&nbsp; public IMoney add(IMoney m) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m.addMoney(this);
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; //
}</tt></pre>

<pre><tt>class MoneyBag implements IMoney {
&nbsp;&nbsp;&nbsp; public IMoney add(IMoney m) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return m.addMoneyBag(this);
&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp; //
}</tt></pre>
In order to get this to compile we need to extend the interface of IMoney
with the two helper methods:
<pre><tt>interface IMoney {
//
&nbsp;&nbsp;&nbsp; IMoney addMoney(Money aMoney);
&nbsp;&nbsp;&nbsp; IMoney addMoneyBag(MoneyBag aMoneyBag);
}</tt></pre>
To complete the implementation of double dispatch, we have to implement
these methods in Money and MoneyBag. This is the implementation in Money.
<pre><tt>public IMoney addMoney(Money m) {
&nbsp;&nbsp;&nbsp; if (m.currency().equals(currency()) )
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new Money(amount()+m.amount(), currency());
&nbsp;&nbsp;&nbsp; return new MoneyBag(this, m);
}

public IMoney addMoneyBag(MoneyBag s) {
&nbsp;&nbsp;&nbsp; return s.addMoney(this);
}</tt></pre>
Here is the implemenation in MoneyBag which assumes additional constructors
to create a MoneyBag from a Money and a MoneyBag and from two MoneyBags.
<pre><tt>public IMoney addMoney(Money m) {
&nbsp;&nbsp;&nbsp; return new MoneyBag(m, this);
}

public IMoney addMoneyBag(MoneyBag s) {
&nbsp;&nbsp;&nbsp; return new MoneyBag(s, this);
}</tt></pre>
We run the tests, and they pass. However, while reflecting on the implementation
we discover another interesting case. What happens when as the result of
an addition a MoneyBag turns into a bag with only one Money? For example,
adding -12 CHF to a Moneybag holding 7 USD and 12 CHF results in a bag
with just 7 USD. Obviously, such a bag should be equal with a single Money
of 7 USD. To verify the problem let's implement a test case and run it.
<pre><tt>public void testSimplify() {
&nbsp;&nbsp;&nbsp; // {[12 CHF][7 USD]} + [-12 CHF] == [7 USD]
&nbsp;&nbsp;&nbsp; Money expected= new Money(7, "USD");
&nbsp;&nbsp;&nbsp; Assert.assertEquals(expected, fMS1.add(new Money(-12, "CHF")));
}</tt></pre>
When you are developing in this style you will often have a thought and
turn immediately to writing a test, rather than going straight to the code.
<p>It comes to no surprise that our test run ends with a red progress bar
indicating the failure. So we fix the code in MoneyBag to get back to a
green state.
<pre><tt>public IMoney addMoney(Money m) {
&nbsp;&nbsp;&nbsp; return (new MoneyBag(m, this)).simplify();
}

public IMoney addMoneyBag(MoneyBag s) {
&nbsp;&nbsp;&nbsp; return (new MoneyBag(s, this)).simplify();
}

private IMoney simplify() {
&nbsp;&nbsp;&nbsp; if (fMonies.size() == 1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (IMoney)fMonies.firstElement()
&nbsp;&nbsp;&nbsp; return this;
}</tt></pre>
Now we run our tests again and voila we end up with green.
<p>The code above solves only a small portion of the multi-currency arithmetic
problem. We have to represent different exchange rates, print formatting,
and the other arithmetic operations, and do it all with reasonable speed.
However, we hope you can see how you could develop the rest of the objects
one test at a time- a little test, a little code, a little test, a little
code.
<p>In particular, review how in the development above:
<ul>
<li>
We wrote the first test, testSimpleAdd, immediately after we had written
add(). In general, your development will go much smoother if you write
tests a little at a time as you develop. It is at the moment that you are
coding that you are imagining how that code will work. That's the perfect
time to capture your thoughts in a test.</li>

<li>
We refactored the existing tests, testSimpleAdd and testEqual, as soon
as we introduced the common setUp code. Test code is just like model code
in working best if it is factored well. When you see you have the same
test code in two places, try to find a way to refactor it so it only appears
once.</li>

<li>
We created a suite method, then extended it when we applied Double Dispatch.
Keeping old tests running is just as important as making new ones run.
The ideal is to always run all of your tests. Sometimes that will be too
slow to do 10 times an hour. Make sure you run all of your tests at least
daily.</li>

<li>
We created a new test immediately when we thought of the requirement that
a one element MoneyBag should just return its element. It can be difficult
to learn to switch gears like this, but we have found it valuable. When
you are struck by an idea of what your system should do, defer thinking
about the implementation. Instead, first write the test. Then run it (you
never know, it might already work). Then work on the implementation.</li>
</ul>

<h1>
<a NAME="TestingPractices"></a>Testing Practices</h1>
Martin Fowler makes this easy for you. He says, "Whenever you are tempted
to type something into a print statement or a debugger expression, write
it as a test instead." At first you will find that you have to create a
new fixtures all the time, and testing will seem to slow you down a little.
Soon, however, you will begin reusing your library of fixtures and new
tests will usually be as simple as adding a method to an existing TestCase
subclass.
<p>You can always write more tests. However, you will quickly find that
only a fraction of the tests you can imagine are actually useful. What
you want is to write tests that fail even though you think they should
work, or tests that succeed even though you think they should fail. Another
way to think of it is in cost/benefit terms. You want to write tests that
will pay you back with information.
<p>Here are a couple of the times that you will receive a reasonable return
on your testing investment:
<ul>
<li>
During Development- When you need to add new functionality to the system,
write the tests first. Then, you will be done developing when the test
runs.</li>

<li>
During Debugging- When someone discovers a defect in your code, first write
a test that will succeed if the code is working. Then debug until the test
succeeds.</li>
</ul>
One word of caution about your tests. Once you get them running, make sure
they stay running. There is a huge difference between having your suite
running and having it broken. Ideally, you would run every test in your
suite every time you change a method. Practically, your suite will soon
grow too large to run all the time. Try to optimize your setup code so
you can run all the tests. Or, at the very least, create special suites
that contain all the tests that might possibly be affected by your current
development. Then, run the suite every time you compile. And make sure
you run every test at least once a day: overnight, during lunch, during
one of those long meetings.
<h1>
<a NAME="Conclusion"></a>Conclusion</h1>
This article only scratches the surface of testing. However, it focuses
on a style of testing that with a remarkably small investment will make
you a faster, more productive, more predictable, and less stressed developer.
<p>Once you've been test infected, your attitude toward development is
likely to change. Here are some of the changes we have noticed:
<p>There is a huge difference between tests that are all running correctly
and tests that aren't. Part of being test infected is not being able to
go home if your tests aren't 100%. If you run your suite ten or a hundred
times an hour, though, you won't be able to create enough havoc to make
you late for supper.
<p>Sometimes you just won't feel like writing tests, especially at first.
Don't. However, pay attention to how much more trouble you get into, how
much more time you spend debugging, and how much more stress you feel when
you don't have tests. We have been amazed at how much more fun programming
is and how much more aggressive we are willing to be and how much less
stress we feel when we are supported by tests. The difference is dramatic
enough to keep us writing tests even when we don't feel like it.
<p>You will be able to refactor much more aggressively once you have the
tests. You won't understand at first just how much you can do, though.
Try to catch yourself saying, "Oh, I see, I should have designed this thus
and so. I can't change it now. I don't want to break anything." When you
say this, save a copy of your current code and give yourself a couple of
hours to clean up. (This part works best you can get a buddy to look over
your shoulder while you work.) Make your changes, all the while running
your tests. You will be surprised at how much ground you can cover in a
couple of hours if you aren't worrying every second about what you might
be breaking.
<p>For example, we switched from the Vector-based implementation of MoneyBag
to one based on HashTable. We were able to make the switch very quickly
and confidently because we had so many tests to rely on. If the tests all
worked, we were sure we hadn't changed the answers the system produced
at all.
<p>You will want to get the rest of your team writing tests. The best way
we have found to spread the test infection is through direct contact. The
next time someone asks you for help debugging, get them to talk about the
problem in terms of a fixture and expected results. Then say, "I'd like
to write down what you just told me in a form we can use." Have them watch
while you write one little test. Run it. Fix it. Write another. Pretty
soon they will be writing their own.
<p>So- give JUnit a try. If you make it better, please send us the changes
so we can spread them around. Our next article will double click on the
JUnit framework itself. We will show you how it is constructed, and talk
a little about our philosophy of framework development.
<p>We would like to thank Martin Fowler, as good a programmer as any analyst
can ever hope to be, for his helpful comments in spite of being subjected
to early versions of JUnit.
<h1>
References</h1>

<ol>
<li>
<a NAME="Gamma, E., et al. Design Patterns: Elements of"></a>Gamma, E.,
et al. Design Patterns: Elements of Reusable Object-Oriented Software,
Addison-Wesley, Reading, MA, 1995</li>

<li>
<a NAME="Beck, K. Smalltalk Best Practice Patterns,"></a>Beck, K. Smalltalk
Best Practice Patterns, Prentice Hall, 1996</li>
</ol>

<hr SIZE=1 WIDTH="100%">
</body>
</html>