summaryrefslogtreecommitdiffstats
path: root/junit4/doc/testinfected
diff options
context:
space:
mode:
Diffstat (limited to 'junit4/doc/testinfected')
-rw-r--r--junit4/doc/testinfected/IMG00001.GIFbin0 -> 6426 bytes
-rw-r--r--junit4/doc/testinfected/IMG00002.GIFbin0 -> 6934 bytes
-rw-r--r--junit4/doc/testinfected/IMG00003.GIFbin0 -> 5992 bytes
-rw-r--r--junit4/doc/testinfected/logo.gifbin0 -> 964 bytes
-rw-r--r--junit4/doc/testinfected/testing.htm617
5 files changed, 617 insertions, 0 deletions
diff --git a/junit4/doc/testinfected/IMG00001.GIF b/junit4/doc/testinfected/IMG00001.GIF
new file mode 100644
index 0000000..ca491c1
--- /dev/null
+++ b/junit4/doc/testinfected/IMG00001.GIF
Binary files differ
diff --git a/junit4/doc/testinfected/IMG00002.GIF b/junit4/doc/testinfected/IMG00002.GIF
new file mode 100644
index 0000000..2fc614f
--- /dev/null
+++ b/junit4/doc/testinfected/IMG00002.GIF
Binary files differ
diff --git a/junit4/doc/testinfected/IMG00003.GIF b/junit4/doc/testinfected/IMG00003.GIF
new file mode 100644
index 0000000..2695af3
--- /dev/null
+++ b/junit4/doc/testinfected/IMG00003.GIF
Binary files differ
diff --git a/junit4/doc/testinfected/logo.gif b/junit4/doc/testinfected/logo.gif
new file mode 100644
index 0000000..d0e1547
--- /dev/null
+++ b/junit4/doc/testinfected/logo.gif
Binary files differ
diff --git a/junit4/doc/testinfected/testing.htm b/junit4/doc/testinfected/testing.htm
new file mode 100644
index 0000000..d11c11c
--- /dev/null
+++ b/junit4/doc/testinfected/testing.htm
@@ -0,0 +1,617 @@
+<!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>
+<br>Note: this article describes JUnit 3.8.x.
+
+<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, fMB1.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>