< Zurück | Inhalt | Weiter >

Chapter 13


JUnit:

Automating Unit Testing


image

Testing may not be your favorite task as a programmer; it probably rates just above documentation. Yet here is a tool that has made testing more bearable and more productive for many Java developers—and not just because it has pretty colors and flashing lights.

image



13.1 WHAT YOU WILL LEARN


• What JUnit is and why it’s getting so much attention.

• How some people test before they start coding.

• How to install and invoke JUnit.

• The major JUnit concepts that you need to understand.

• What assertions are available in JUnit.


295


13.2 JUNIT: WHY ALL THE FUSS?


JUnit is a framework for unit tests. It consists of a handful of classes which you can use to build bunches of test cases for testing your application. JUnit also comes with three test “runners” for running your tests and reporting the test results. So why all the fuss? Why has JUnit been so much in the technical forefront the last year or two?

Start with a straightforward idea, well executed, that can help almost any programmer working on any application. Make it something that can be inte- grated incrementally into existing projects. Make it robust enough to be used for projects starting “from scratch.” Give it a simple but pleasing GUI, and put it to work on a few high-profile projects. Give it some good press coverage. And you’ve got a winner: You’ve got JUnit. Besides, it really does help you get useful work done; it makes writing tests a little less work and a little more enjoyable. And working with well-tested code is its own reward—a satisfying experience.


13.3 DESIGN THEN TEST THEN CODE


This is the slogan of the test-oriented crowd, and if it sounds a bit impossible, it is. It’s hype—it got your attention, and there is a bit of truth to it, but don’t take it too literally.

The approach espoused by the “Testing First” crowd is to start, like all good software development efforts, with design. But once you have pieces de- signed, move directly into testing. Now you don’t have any code that can be tested yet, but you can start writing your tests. Then—although the tests will fail, as there is no code to run yet—you can begin keeping score on your progress by running these tests as code gets implemented.



NOTE

Some people like to tout the use of JUnit as an automated tool to track progress, but that’s a little hard to do when you can’t compile your tests because the classes they need don’t yet exist. However, if you document your design of a class by (among other things) creating an empty version of the source, with Javadoc comments for the class and whatever methods you have come up with so far, well, then you’ve got something that will compile, and thus can be used for tracking progress. It also makes great, tangible documentation. Our point here, though, is that you are doing some coding before you begin testing. It’s really more of a back-and-forth between coding and testing.

image


Let’s apply that approach to our previous design discussion. We’ve de- scribed an Account class in our design discussion. It needs a name, an owner, and an amount of money when created. It should have a method to create subaccounts, ones that are connected to this account and get allocated some or all of the main account’s money.

Example 13.1 is the basic structure of our Account class.

That’s enough to begin writing a test. We have described the constructor, with the three parameters that it will need. We’ve also described a method on the Account object, one that will create subaccounts. That gives us enough information to write a test that will create an account and then create subac- counts of that account. We can test to see if the accounts are created properly (i.e., are not null) and if the subaccounts use up all the money of the parent account.

When you “test then code,” you begin to use the objects that you have designed without getting bogged down in their implementation. You are, in effect, describing their external interfaces without implementing them. You are also beginning to use the classes as a user might, though a tester’s use is a bit different than the way an application might use them. However, as a user of these classes you are beginning to test the design, by testing the results of the use cases—are these classes really usable?

You may discover that you need some additional functionality. In our ex- ample, we can see from the description of our test that we will need a getter method on the account to return the amount of money that remains unallocat- ed to subaccounts. Then we can test to see if it gets used up properly.

There are many more test cases that we could develop for the Account class, but let’s use just these for now, so that the size of our test case is manageable.

Our next step is to get JUnit installed before we get too deep into developing our test cases. That will give us something to run these tests.


13.4 INSTALLING AND RUNNING JUNIT


It’s rather simple to install a standalone version of JUnit. We download a ZIP file from the JUnit Web site, then unzip it into a directory. Adding the JUnit JAR file to your CLASSPATH is all that’s needed to make JUnit available for you to run it.


image

Example 13.1 The bare bones of our Account class

package net.multitool.core;


import net.multitool.util.*; import java.util.*;


/**

* The basic Account class for our budgeting example; this is the

* first-cut "implementation" where we have just transferred our

* design into Java code. We can use this much to generate Javadocs

* and also to begin our JUnit testing (design, test, code).

*/


public class Account

{

private String name; // a name to identify this account private User owner; // the user assigned to this account private SAMoney total; // total amt allocated to this account private HashMap children; // the collection of subaccounts,

// by name

private Account parent; // it has this account as a child


/**

* Create an account, with a pool of dollars to budget.

* Use this constructor to create the master account.

* Use "createSub" to create children of this account.

*/ public

Account(String name, User owner, String total)

{

}


/**

* Create a new subaccount (i.e., child), given a name

* and an amount. The child is connected to the parent.

*/

public Account

createSub(String name, String amt)

{

return null; // so it compiles


} // createChild


} // class Account


image


 


13.4.1 Downloading and Unzipping

13.4.2 Using JUnit

13.5.1 JUnit Assertions

13.5.2 Running a Test Case