that each has at least the minimum number needed to get a real average. We then generate a
random result for each of these at bats. We build a simple Hashtable to allow us to translate
between our random integer value and an at-bat result. Note that we plan on using the atBat()
method in the Batter interface to initialize these records, so we will need to test that method
using some other data set. That set will need to feed a known set of at-bat combinations to
batter objects, and then see whether the resulting statistics reflect the known state of the input.
If that test works, we will be able to trust (more) the tests we are running that depend on the
correctness of the atBat() method.
Our initialization is pretty simple, only creating local objects that we can leave to the garbage
collector to clean up. If we were doing something that used resources such as file descriptors
or sockets, however, we would need to clean up after ourselves at the end of the test run. To do
this, JUnit looks for a method with the annotation @After . Don't neglect to write this method
if you are using limited resources in your tests, as there is no guarantee that your tests will be
run by themselves. JUnit is set up to run groups of tests together, so yours might be part of a
much larger test run. You might not use up all of the resources on the test machine, but if you
keep any after your test run and others do the same, the cumulative effect may be to build a
test suite that is itself unreliable.
Sometimes it takes a lot of code to do a reasonable test. This is especially true for code like
the StatRecorder and StatReporter that we saw earlier that forms a client-server system
meant to operate over the network. To test either of these requires that we emulate the other
side of the network inside of our tests. This doesn't mean that we have to reimplement either
the client or the server, but we do need a local implementation of code that will take the appro-
priate inputs and give the appropriate outputs. Since the test code knows the kinds of inputs
and outputs expected, this can be considerably easier than reimplementing the whole of the
client and server. But it does take some thought.
Writing good test suites is a subject that is often ignored, but is an interesting programming
problem in its own right. This subject has gotten more interest with the advocacy of test-driven
development, but it really doesn't matter whether you write the tests before the code, or the
code and then the tests, as long as both get written. Coming up with a really good test suite is
a difficult design problem that is often as challenging as writing the code being tested. I won't
to change, and easier to understand. The great thing about JUnit is that it makes those tests
easier to write, assemble into suites, and run.