Unit Testing with JBuilder Part II by Charlie Calvert

By: Charlie Calvert

Abstract: This is Part II of a three part article about a technology you can use in JBuilder called unit testing. Unit testing helps you easily confirm the validity of your code.

Unit Testing with JBuilder Part II by Charlie Calvert

Copyright © 2002 by Charlie Calvert

This is the second part of a three part article .

Adding Tests of the CodeBox Class

Now that you have a feeling for how JUnit works, the next step is to create a more complex test. In particular, we will build tests for the StringBox unit found in the free Elvenware CodeBox jar file that ships on the CD for my new JBuilder book. You can download the code from source forge.

Add the Elvenware code to the Paths page of the Project | Project Properties dialog, as shown in Figure 4. After you install the code for this book, you should have a directory called something like jbbooksrcpersonal on your system. It is this directory that you want to add to your source path.

Figure 4: Setting up the source path for your JBuilder project so that you can access the code in the Elvenware packages.

After you click ok in the Project Properties dialog, you will probably need to press the refresh button (fourth from the left) in the tool bar above the project pane so that you can see the com.elvenware.* packages, as shown in Figure 5.

Figure 5: When you press the refresh button over the project pane, you should be able to see the new packages you have added to your source path.

Open up the StringBox class from the com.elvenware.codebox package. Make sure it is focused in the content pane of the IDE. From the JBuilder menu select File | New, and turn to the Test page. Run the first item, called Test Case.

On the first page of the Test Case wizard, select all the methods from StringBox.java except sayMouse, as shown in Figure 6. Press the next button.

Figure 6: Selecting the methods from the StringBox class that you want to test.

On this second page of the Test Case wizard, make sure that the TestStringBox class ends up in the unittesting package, and not in com.elvenware.codebox, as shown in Figure 7. This is determined by the top field in the dialog, labeled Package. Everything in the codebox package is likely to end up in CodeBox.jar. The test programs, however, do not belong in the jar file. As a result, you probably want to keep them out of the codebox package lest they end up in the jar file by mistake. To do this, just use the Package field to put them in the unittesting package. When you press the Finish button, the code shown in Listing 3 will be created.

Figure 7: Use the Package field to determine the package where your test case will be stored.

Listing 3: The code generated by JBuilder for testing your class.

package com.elvenware.codebox;

import junit.framework.*;



public class TestStringBox extends TestCase
{

  public TestStringBox(String s)
  {
    super(s);
  }

  protected void setUp()
  {
  }

  protected void tearDown()
  {
  }

  public void testGetFirstWord() { 
    String value1=  "STRING0";
    String stringRet = StringBox.getFirstWord(value1);
  /** @todo:  Insert test code here.  Use assertEquals(), for example. */
  }
  public void testIncludeCR() { 
    String value1=  "STRING0";
    String stringRet = StringBox.includeCR(value1);
  /** @todo:  Insert test code here.  Use assertEquals(), for example. */
  }
  public void testIncludeTrailingDelimiter() { 
    String fileName1=  "STRING0";
    String stringRet = StringBox.includeTrailingDelimiter(fileName1);
  /** @todo:  Insert test code here.  Use assertEquals(), for example. */
  }
  public void testIntToStrPad0() { 
    int value1=  0;
    int paddings2=  0;
    String stringRet = StringBox.intToStrPad0(value1, paddings2);
  /** @todo:  Insert test code here.  Use assertEquals(), for example. */
  }
  public void testReverse() { 
    String stringToReverse1=  "STRING0";
    String stringRet = StringBox.reverse(stringToReverse1);
  /** @todo:  Insert test code here.  Use assertEquals(), for example. */
  }
  public void testShorten() { 
    String s1=  "STRING0";
    int charsToCut2=  0;
    String stringRet = StringBox.shorten(s1, charsToCut2);
  /** @todo:  Insert test code here.  Use assertEquals(), for example. */
  }
  public void testStripFirstWord() { 
    String value1=  "STRING0";
    String stringRet = StringBox.stripFirstWord(value1);
  /** @todo:  Insert test code here.  Use assertEquals(), for example. */
  }
}


You can see that there is one test method generated for each method in the StringBox class. All that is left for us to do is tweak some variables and compose the assertEquals or assertTrue method that will prove that the generated tests work. The test case that I came up with is shown in Listing 4.

Listing 4. A JUnit test case for the StringBox class.

package unittesting;

import junit.framework.*;
import com.elvenware.codebox.*;

public class TestStringBox extends TestCase
{

	public TestStringBox(String s)
	{
		super(s);
	}

	protected void setUp()
	{
	}

	protected void tearDown()
	{
	}

	public void testGetFirstWord()
	{
		int value = 1;
		String theWord = "OneWord";
		String result = StringBox.getFirstWord(theWord);
		System.out.println("GetFirstWord: " + result);
		assertTrue(result.equals(theWord));
	}

	public void testGetFirstWord2()
	{
		int value = 1;
		String theWord = "";
		String result = StringBox.getFirstWord(theWord);
		System.out.println("GetFirstWord: " + result);
		assertTrue(result.equals(theWord));
	}

	public void testGetFirstWord3()
	{
		int value = 1;
		String theWord = "Two words";
		String result = StringBox.getFirstWord(theWord);
		System.out.println("GetFirstWord: " + result);
		assertTrue(result.equals("Two"));
	}

	public void testGetFirstWord4()
	{
		int value = 1;
		String theWord = " A then this is another test";
		String result = StringBox.getFirstWord(theWord);
		System.out.println("GetFirstWord: " + result);
		assertTrue(result.equals("A"));
	}

	public void testIncludeCR()
	{
		String value1=  "STRING0";
		String stringRet = StringBox.includeCR(value1);
		assertTrue(stringRet.endsWith("n"));
	}

	public void testIncludeTrailingDelimiter()
	{
		String fileName1=  "STRING0";
		String stringRet = StringBox.includeTrailingDelimiter(fileName1);
		assertTrue( (stringRet.endsWith("")) || (stringRet.endsWith("/")) );
	}

	public void testInToStrPad0()
	{
		int value = 1;
		int paddings2=  3;
		String result = StringBox.intToStrPad0(value, paddings2);
		System.out.println("IntToStrPad0: " + result);
		assertTrue(result.equals("001"));
	}

	public void testIntToStrPad0()
	{
		int value1=  0;
		int paddings2=  0;
		String stringRet = StringBox.intToStrPad0(value1, paddings2);
		assertTrue(stringRet.equals("0"));
	}

	public void testReverse()
	{
		String stringToReverse1=  "STRING0";
		String stringRet = StringBox.reverse(stringToReverse1);
		assertEquals(stringRet, "0GNIRTS");
	}

	public void testShorten()
	{
		String s1=  "STRING0";
		int charsToCut2= 4;
		String stringRet = StringBox.shorten(s1, charsToCut2);
		assertEquals(stringRet, "STR");
	}

	public void testStripFirstWord()
	{
		String value1=  "STRING0";
		String stringRet = StringBox.stripFirstWord(value1);
		assertEquals(stringRet, "");
	}

	public void testStripFirstWord2()
	{
		String value1=  "";
		String stringRet = StringBox.stripFirstWord(value1);
		assertEquals(stringRet, "");
	}

	public void testStripFirstWord3()
	{
		String value1=  "This time";
		String stringRet = StringBox.stripFirstWord(value1);
		assertEquals(stringRet, "time");
	}

	public void testStripFirstWord4()
	{
		String value1=  "This time is true";
		String stringRet = StringBox.stripFirstWord(value1);
		assertEquals(stringRet, "time is true");
	}
}

Perhaps the most interesting thing about this code is the amount of repetition in it. For instance, there are four test cases for both the stripFirstWord and getFirstWord methods. The tests include making sure the methods work correctly when passed a multi-word string, a string with one word in it, and an empty string. The more inventive you are in coming up with tests, the more likely it is that your code will be bug free. Needless to say, you should add new tests the moment you find a bug in any of these routines. The extreme programming people would say that you should add the test even before you try to fix the bug. The first step is to produce a test to check for error conditions, the second step is to fix the bug itself.

NOTE: It is quite literally true that many extreme programming advocates would recommend that the first thing you do when starting a new project is write a test. As soon as you have the test in place, you can begin attempting to write a program that will pass the test. All of this is explained in more depth on http://www.extremeprogramming.org. Another interesting extreme programming resource is found here: http://ootips.org/xp.html.

These tests can help you define exactly what a method should do. For instance, I had not really made up my mind if the stripFirstWord method should return one word or an empty string if you pass in a string that contains only one word. Creating test cases forced me to come to terms with this method and define how it should behave. (I decided that it should return an empty string.)

Another important feature of tests like this is that they give you confidence when it comes time to fix bugs in your code, or try to enhance the performance of your code. If I need to improve the getFirstWord method, I can proceed with confidence, because I know that these tests will catch at least the most obvious bugs I might introduce while attempting to enhance the code.

One of the key ideas behind extreme programming is that it is actually fun to write tests. You do just a little bit of work, and then almost instantly you begin to get feedback. For once, you don't have to worry that the code you are writing might slow down your program. Instead, you should just exercise your creativity to the fullest extent possible, and generate as many tests as possible. This is something you should integrate into your daily work habits. It is, however, also something useful that you can do when you just don't have the energy for more complex tasks. Have fun with it!

Testing Methods that Return Strings

For those times when you are not feeling very creative, you should try to come up with some rules that can help you compose tests. For instance, when testing a string routine, you should always generate code for at least two methods:

  • Test the method when passing in a normal string.
  • Test the method when passing in an empty string.

From the StringBox class, here are two examples of what I mean:

 public void testReverse()
  {
    String value1=  "abc";
    String stringRet = StringBox.reverse(value1);
    assertEquals(stringRet, "cba");
  }

  public void testReverseEmpty()
  {
    String value1=  "";
    String stringRet = StringBox.reverse(value1);
    assertEquals(stringRet, "");
  }

There are simple rules like these for mathematical methods as well. For instance, always test your code with 0 as a parameter, and with both negative and positive parameters.

Test Fixtures

You have now seen the first two pages in the Test Case wizard. The final page in the wizard is for creating something called fixtures. Fixtures are used to help you set up and tear down test cases. The fixture in question can be any class or set of variables that you want to use in the set up and tear down methods to help you run your tests. These fixtures might do nothing more than initialize variables.

Note that the setup and teardown methods will be called in between each test that makes up your test case. That way you can be sure that all the tests are run against an object that is correctly initialized. For instance, if you are running tests against a remote server, your fixture code might connect you to that server. Then you can safely run tests against all of the methods on that server.

For more information on Fixtures, visit the well documented www.junit.org web site.

This is the end of Part II. Part I and Part III are now available.


Server Response from: ETNASC04