http://www.developer.com/

Back to article

Automated Unit Testing Frameworks


June 23, 2004

About the Frameworks Series

Beside the Java language, a world of Java frameworks exists. These frameworks can afford substantial improvements in programmer productivity and enhance the quality, performance, reliability, and interoperability of different Java applications. Fortunately, many of these popular and widely used frameworks are open source projects so anyone can benefit from them if he can invest some time in learning when and how to use such frameworks. This article, the third one in the frameworks series, encourages Java programmers to employ unit tests to get robust code quickly. It also introduces JUnit, an open source Java framework for unit testing any Java code.

Previously Published Articles in This Series

Introduction

Without unit testing, a programmer will write a low-level class and get it compiled to assume that the code would work properly. At the end of the day, the programmer may end up with a group of related and dependent classes that are all compiled without errors but unfortunately the final program is not working at all or at least the resultant program is not working as planned. To deal with a situation like this, a programmer will spend a lot of time debugging and correcting the code.

During the debugging process, the programmer may detect that many of the assumptions he made about the correctness of some pieces of code were wrong and he may have to review each class and verify that it works properly in isolation of the other code.

Based on this scenario, you have the opportunity to save time and effort if you replace the assumption that each piece of code would work properly with the knowledge that each piece of code is already working properly. This is primarily what unit testing can afford you.

What Is Unit Testing?

A unit test exercises "a unit" of production code in isolation from the full system and checks that the results are as expected. The size of the unit may vary between a class and a package. In the case of Java, a unit usually refers to a single class.

The importance of unit testing had increased with the intervention of extreme programming, a lightweight software methodology proposed to reduce the cost of software development. In this approach, a developer should write unit tests even before writing the actual code.

Whether you will follow a test-driven development approach or not, it's your responsibility, as a developer, to write unit tests to check your own code. Nowadays, unit testing has become an integral part of any professional Java developer toolkit.

Why Should You Use Unit Testing?

Before listing some of the benefits you will gain when applying unit testing to your code, let's explain how you can employ unit testing to maximize your profits.

In Java, you will need to test every Java class you implement. The question is: Which should I write first, the code or the test? The answer is: You could start with implementing your class and getting it compiled before writing the necessary unit tests. However, a better approach, named Test-Code-Simplify cycle, suggests following these steps:

  • Write a single test.
  • Compile it. It shouldn't compile because you haven't written the implementation code it calls.
  • Implement just enough code to get the test to compile.
  • Run the test and see it fail.
  • Implement just enough code to get the test to pass.
  • Run the test and see it pass.
  • Refactor for clarity.
  • Repeat.

By following this approach, unit testing will not only help you to write robust code and decrease your bugs but it also will assist you to improve your design, and reduce the cost and fear of changing working code. Moreover, it will make your development faster and will act as a concise executable documentation of your code.

Automate Your Unit Tests with JUnit

JUnit is the defacto standard for testing any Java code. It was invented in 1999 and many developers have already practiced this very simple and easy-to-learn and use framework. JUnit relies on a number of classes and interfaces that will be summarized in the next sections.

TestCase

The abstract class, TestCase, is the central class in the JUnit framework. A test case composes a group of tests that share the same fixture. Fixtures are implemented in test cases and are used to set up and tear down objects that are common to the tests in the test case.

Assert

The JUnit Assert class provides a group of methods for asserting that some condition is true. The following is a list of the most used Assert class methods.

  • assertEquals ([String message], expected, actual)
  • assertSame ([String message], expected, actual)
  • assertTrue ([String message], boolean condition)
  • fail ([String message])

The optional message parameter is a message to be reported in case of a failure. The two parameters, expected and actual, represent the value you want to see and the actual value produced by the code under test. The type of these two parameters could be any primitive data type (for example, int, float, double, and so forth) or Object.

Test Suite

Test suites are collections of tests. Dynamically, each test case has a test suite composed of all the tests implemented within this test case. However, you may statically customize the test suite. For example, you can force a specific order of tests, remove some tests, or add tests from other test cases.

JUnit in Action

In this section, I will show you a step by step example to write JUnit tests. To run this example, you need to obtain JUnit from its official site at www.junit.org. Installing JUnit is very simple; just unzip the downloaded file and place junit.jar in your CLASSPATH.

The class to be tested is a Java Queue class as presented in the article "Queue: A missed java.util Class." The public interface to the Queue class is shown in Listing 1.

public class Queue {
   private LinkedList items;
   public Queue()
   ...
   public Object enqueue (Object element)
   ...
   public Object dequeue ( )
   ...
   public int size ( )
   ...
   public boolean empty ( )
   ...
   public void clear ( )
   ...
}

Listing 1: Fragment of the Queue class

Step 1: Imports

You need to import the junit.framework package to write your test case.

import junit.framework.*;

Step 2: Implement a Test Case

A test case is a class derived from junit.framework.TestCase.

public class TestQueue extends TestCase  {

   public TestQueue (String name) {
      super (name);
   }

   public static void main ( String[] args)  {
      junit.textui.TestRunner.run (suite());
   }
}

Just use the constructor to invoke the TestCase constructor. The main() method is used to run the test runner textual interface.

Step 4: Define and Initialize the Fixture

In this example, we need to create two Queue objects, an empty queue and a queue of three Integer objects. Each test in the test case may send some messages to one of the two objects. So, we have to re-initialize the two objects before running each test. In other test cases, you also may need to tear down some objects after running each test (for example, close a network or database connection). JUnit provides two methods, setUp() and tearDown(), that you can override in your test case to initialize and tear down any member variables in the test case.

To implement the TestQueue fixture, add two private Queue references and override the setUp () method.

private Queue empty_queue;
private Queue queue;

   protected void setUp() {
   empty_queue = new Queue();
   queue       = new Queue ();
   queue.enqueue (new Integer (1));
   queue.enqueue (new Integer (2));
   queue.enqueue (new Integer (3));
}

Step 5: Compose a Test Suite

Add the following static method to your test case.

public static Test suite() {
   return new TestSuite(TestQueue.class);
}

This way, you will make use of the JUnit Reflection-driven API and you will be restricted to start the name of any test with the word "test." In addition, you can't assume anything about the order in which your tests will be run.

If you want to force a specific order of tests, not use the test's naming convention, run some other tests from other test cases, or eliminate some tests in the test case. You may write some code like this:

public static Test suite ( ) {
   TestSuite suite= new TestSuite("Customized Test Suite");
   suite.addTest(new TestSuite(TestQueue.class));
   suite.addTest(TestQueue2.suite());
   return suite;
}

Step 6: Write Tests

In JUnit, each test is a public void method with no parameters. The following two tests will be used to test the size and the enqueue () methods.

public void testSize() {
   assertEquals(queue.size(),3);
   assertEquals(empty_queue.size(), 0);
}

public void testDequeue() throws EmptyQueueException {
   int size = queue.size();

   try {
        empty_queue.dequeue();
   } catch (EmptyQueueException e) {
        assertTrue (true);
   }

   Integer i = (Integer) queue.dequeue();
   assertEquals (i, new Integer (1));
   assertEquals ("size not decremented",queue.size(), size - 1);
}

The two tests are self-explanatory; you may download the complete source available at the end of this article, examine the remaining tests, modify the tests, and follow the last step to run the tests.

Step 7: Run the Test Suite

To run your tests using the command line test runner, type:

Java TestQueue

To run the JUnit Swing test runner, type:

java junit.swingui.TestRunner TestQueue1

JUnit Test Runner

Figure 1: JUnit Test Runner

JUnit Extensions

One of the main design goals of JUnit is to be simple and fast. Due to these requirements, some features were not supported by JUnit. For example, arrays equality and accessing the private section of an object were not supported.

Because it's a framework, JUnit is extensible. Anyone can easily extend JUnit to incorporate new features. Many frameworks that extend the functionality of JUnit or just decorate it are available for free as open source projects. Table 1 summarizes some of these frameworks.

Table 1: Some JUnit Extensions
Framework Description
Cactus A simple test framework for unit testing server-side java code (Servlets, EJBs, Tag Libs, Filters, ...).
HTTPUnit Provides an easy way to write automated functional tests for Web sites, regardless of the technology used to implement them.
JunitPerf A collection of JUnit test decorators used to measure the performance and scalability of functionality contained within existing JUnit tests.
xmlUnit Allows you to compare XML documents and strings.
EasyMock A framework for dynamically creating mock object at runtime.

Source Code

Download the accompanying source code here.

Acknowledgements

The author would like to thank Rosemarie Graham for suggesting the idea of this series and Developer.com for publishing the series.

About the Author

Yasser EL-Manzalawy has been a Java programmer and instructor since 1998. He is currently an assistant Lecturer at the Systems & Computers Engineering Department, AZHAR University, Cairo. His Ph.D. research project aims to extend the Java language for agent-based systems.

Related Links

www.junit.org: the official junit site where you can freely download junit and check a large number of articles, books, and related documents.

"Top 12 Reasons to Write Unit Tests," by Eric M. Burke and Brian M. Coyner.

"JUnit best practices," by Andy Schneider.

"JUnit and Its Extensions Make Unit Testing Your Java Code Much Easier," by Bryan Dollery.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date