Chapter 6.  Abstract class junit.framework.TestCase

If you have test(s), each grouping of which needs independent resource(s) set up the same way (to avoid side-effects or for other reasons), then you can satisfy that need by making a setUp method and a cleanup method. For every grouping needing these resources set up, you run

    setUp();
    assert(something);
    assert(somethingelse);
    cleanup();

JUnit accomplishes this by having you extend the TestCase class and grouping your tests into methods that share those resource(s); and using the methods setUp() and tearDown() for the obvious purposes. All the tests in one method share the same setUp-ed resources. The setUp and tearDown method implementations need to match the signatures in the API spec for TestCase. This sequence of setUp() + yourTestMethod() + tearDown() is the exact purpose of Test.run().

The tricky thing to understand is, the only elemental Tests that can actually be run are TestCase implementations that were created with TestCase(String). Since TestCase is an abstract class, you can't just call TestCase(String)-- you have to implement TestCase and make a constructor that does super(String). The object "x" below is a runnable test.

    class X extends TestCase {
    ...
        public X(String s) {
            super(s);
        }

Then, in any class...

        X x = new X("astring");

Not very intuitive, but that's how it is. The string argument to TestCase(String) must be a method in the constructing class. For example, if X extends TestCase, then new X("astring" ) will have a runtime failure unless X has a method named "astring" that takes no arguments. This concept is very weird, but the concept is crucial to be able to figure out the many different ways that one can code JUnit unit tests. Therefore, let's solidify this with an exercise.

I urge you to do this very simple exercise to prove to yourself that TestCase instances created like new X("astring") are really runnable Tests.

  1. Create a public class X that extends junit.framework.TestCase.

  2. Make a public constructor for X that takes a String argument, and which just calls the super constructor of the same form.

  3. Make an object method named "meth" that takes no arguments and throws Exception. Just have it print out something so that you can see when it is invoked.

  4. Add a public static void main(String[]) method that throws Exception so that you can invoke the program.

  5. In your main() method, run (new X("meth")).run();

This proves that new X("meth") really creates a runnable Test, and that when it runs, the following happens.

    anonymous.setUp();
    anonymous.meth();
    anonymous.tearDown();

Note that the setUp() and tearDown() methods executed are from the same exact class that your method ("meth" in our example) resides in. You can instantiate the Test and run it from some other class, but the three methods that get run come from the TestSuite-implementating class. An important implication of this is, if you code any setUp or tearDown method in a TestCase class, you should only put test methods into this class which need your setUp/tearDown methods to run before/after it. If you have a method which doesn't need these prep/cleanup actions, then move them into a TestCase that doesn't implement setUp/tearDown.

TestCase itself extends Assert, so your individual tests can be coded like assertEquals(this, that); , since this is now an Assert.

If you understand everything so far, then you understand JUnit much better than most JUnit users do.

You just run

    (new myTestCase("myTestMethodName")).run();

for every test you want to run. You can have as many TestCase implementation files with as many test methods as you want in each one, in addition to non-test methods. In these classes or in other classes, you can invoke any of these tests. You could have a test manager class with a main(String[]) method that invokes a variety of test methods in any of your TestCase implementation files.

At this point, you can write and execute all the JUnit tests you could ever want to. You probably want to use a JUnit supplied Test Runner though, to collect and display test results as it runs tests. We'll get to that later.