«    »

Java Unit Testing Tutorial: Write Your First Unit Test

In this section of the Java Unit Testing Tutorial you will write your first unit test and get it to execute successfully.

Tutorial Introduction Previous: Initial Setup

Determine What to Test

Before you can write your first unit test you need some code to test. If you are trying this in your own project, then select a class with a method that needs unit testing. How do you know what code needs testing? The general criteria is this: when you look at the code for the class, if there is any logic which you are uncertain will work in all scenarios, then you should write unit tests for that logic. To be specific, one-line methods like trivial getter and setter methods do not need testing – it is obvious that they will work. Most methods longer than a few lines of code and especially those with conditionals or loops usually warrant unit tests.

You must be wary of false confidence in your code. You need to be one hundred percent confident that the code works as intended across all scenarios – including bad input, system failure, null references, etc. - in order to decide it does not need a unit test.

As you are choosing your class to test, it will be helpful for this first time to choose a class with minimal dependencies: the class should require a minimum (ideally none) of other classes / objects to be supplied for the class to be used.

In the remainder of this section I will refer to the class and method you have chosen as class YourClass located in package your.package and method yourMethod().

To provide a concrete example I will be testing the class ParserHelper from the example project UnitTestingTutorial. The code for this class is shown below:

// Copyright 2009 by Basil Vandegriend.  All rights reserved.
package com.basilv.unittestingtutorial.writeyourfirsttest;

/**
 * Helps parse a set of tokens. Maintains an internal index into the
 * supplied tokens to determine which token all the methods will act on. 
 * This index must be advanced by the caller.
 */
public class ParserHelper
{
  static final String DEFINITION_SEPARATOR = "->";

  private String[] tokens;

  private int currentTokenIndex;

  public ParserHelper(String[] tokens) {
    this.tokens = tokens;
  }

  public void nextToken() {
    currentTokenIndex++;
  }

  public String extractTaskName() {
    if (!haveMoreTokens()) {
      throw createParseException("Expected task name but no further input supplied.");
    }
    return currentToken();
  }

  public String extractRollupGroup() {
    if (!haveRollupGroup()) {
      throw createParseException("Expected a rollup group of the form '['']'.");
    }
    String token = currentToken();
    String group = token.substring(1, token.length() - 1);
    if (group.length() == 0) {
      throw createParseException("An empty rollup group '[]' was specified.");
    }
    return group;
  }

  public boolean haveRollupGroup() {
    if (!haveMoreTokens()) {
      return false;
    }
    String token = currentToken();

    return (token.startsWith("[") && token.endsWith("]"));
  }

  public void expectSeparator() {
    if (!haveSeparator()) {
      throw createParseException("Expected separator '"
        + DEFINITION_SEPARATOR + "'.");
    }
  }

  private boolean haveSeparator() {
    if (!haveMoreTokens()) {
      return false;
    }
    return DEFINITION_SEPARATOR.equals(currentToken());
  }

  private boolean haveMoreTokens() {
    return currentTokenIndex < tokens.length;
  }

  private String currentToken() {
    return tokens[currentTokenIndex];
  }

  private RuntimeException createParseException(
    String parseErrorMessage) {
    int tokenNumber = currentTokenIndex + 1;
    String message = "Error parsing token #" + tokenNumber
      + ":" + parseErrorMessage;

    return new RuntimeException(message);
  }
}

This class has a number of methods. Which one should I test? The nextToken method is trivially correct so I skip it. The extractTaskName method is almost simple enough to skip, but I resist the temptation and choose it. (Because the method is simple it will be easy and quick to test.)

Create the Unit Test Skeleton

Before you can write the actual unit test code to invoke the method you chose and verify the results, you must create the skeleton code that JUnit needs to execute the unit test. This skeleton test code follows a standard pattern which is explained in the following steps:

  1. Create a test class for class YourClass. The test class will be located in the same package your.package but under the source directory "src/test" instead of "src/main". Name the class YourClassTest. If the class you are planning to test is located on the file system at "src/main/your/package/YourClass.java" you will now have a test class located at "src/test/your/package/YourClassTest.java".
  2. Populate the test class using the following template. Include the import statements. You will need to change the name of the class in the template to YourClassTest.
    import static org.junit.Assert.*;
    import org.junit.*;
    
    public class TemplateClassTest
    {
      @Before
      public void setUp() throws Exception {
    
      }
    
      @After
      public void tearDown() throws Exception {
    
      }
    
      @Test
      public void templateMethod() throws Exception {
        fail("TODO: Write this test.");
      }
    
    }
    

    This template provides a single test method identified by the @Test annotation. JUnit will treat this method as a test and execute it as part of the project's suite of tests.

    The @Before and @After annotations indicate methods that are to be invoked before and after the test method. Collectively these two methods represent what is called a test fixture, and are used to create a common set of objects shared across multiple tests.

  3. Rename method templateMethod() to yourMethod(). The test code you will write will go in this method.
  4. Run the unit tests for the project to confirm the test skeleton was created properly. The Initial Setup section of the tutorial explains how to do this in detail, but as a quick reminder open the menu for the Run icon in the tool bar and choose the JUnit entry named after your project. The tests should now run (without the warning message about having no tests that you encountered during initial setup).
  5. The results of running JUnit tests are displayed within an Eclipse view titled "JUnit". See the image below. (Your JUnit view may be laid out differently depending on your screen and options, but will contain the same information.) The most important element of the view is the horizontal red bar near the top, which is a striking visual indicator of the overall status of the tests: red indicates that at least one test was unsuccessful, whereas green is displayed only if all the tests are successful. Above the bar are the summary statistics that indicate the number of tests that ran (1 / 1), the number that encountered an error (0), and the number that failed to meet the expected results (1). Below the red bar in the first pane is the hierarchy of tests, usually filtered to only show the unsuccessful tests. The second pane shows the stack trace of the point of failure or error for the test selected in the first pane.
    Eclipse JUnit View with failure
    Your single test is failing because the test method provided in the template includes the following code:
    fail("TODO: Write this test.");

    The fail() method is a static method from the JUnit Assert class that causes the test to fail if it is executed. Including this code in the template provides an automatic reminder to actually write the test as it starts out failing.

Returning to the example project, since I am planning to test the class ParserHelper I need to create a test class ParserHelperTest. The skeleton code for this test class is located below:

// Copyright 2009 by Basil Vandegriend.  All rights reserved.
package com.basilv.unittestingtutorial.writeyourfirsttest;

import static org.junit.Assert.*;
import org.junit.*;

public class ParserHelperTest
{
  @Before
  public void setUp() throws Exception {

  }

  @After
  public void tearDown() throws Exception {

  }

  @Test
  public void extractTaskName() throws Exception {
    fail("TODO: Write this test.");
  }
}

Because I plan to test the method extractTaskName on ParserHelper, I have given the test method the same name.

Write the Test Code

You are now ready to write the actual test code that will exercise the class you are testing and verify the results. While the specifics will of course vary from class to class and method to method, there are three common phases that must be performed in each case: setup, execution, and verification.

  1. Setup: Create the object to be tested and configure its initial state prior to being tested. This includes configuring any required dependencies, which includes parameters to the method being tested.
  2. Execution: Invoke the method being tested and capture the return result.
  3. Verification: Confirm that the method performed the expected actions. This is done by invoking appropriate methods of the JUnit Assert class such as the fail() method introduced above. If an expectation fails then the JUnit method will throw an special exception indicating the test has failed. Execution of the test method will stop and JUnit will record a failure for the test. If at any point in the test method any other exception is unexpectedly thrown (i.e. not caught within the test method) JUnit will record an error for the test.

To demonstrate how to implement these steps I continue the example from above to test the ParserHelper.extractTaskName() method.

  1. Setup: I need to create an instance of ParserHelper, which requires an array of tokens to be supplied to its constructor. I chose to supply a single token, which will be the task name that I expect to have returned from the method.
        String expectedTaskName = "test";
        ParserHelper helper = new ParserHelper(new String[] { expectedTaskName });
    
  2. Execution: I invoke the method under test and record the actual result.
     String actualTaskName = helper.extractTaskName();
    
  3. Verification: I use the JUnit assertEquals method to verify that the actual task name returned matches what I expect.
        assertEquals(expectedTaskName, actualTaskName);
    

The completed test method is shown below:

  @Test
  public void extractTaskName() throws Exception {
    // Setup
    String expectedTaskName = "test";
    ParserHelper helper = new ParserHelper(new String[] { expectedTaskName });
    
    // Execution
    String actualTaskName = helper.extractTaskName();
    
    // Verification
    assertEquals(expectedTaskName, actualTaskName);
  }

This concludes the tutorial. There is, however, still much more to learn about unit testing. Check here regularly or subscribe to this site's feed to find out when new sections are added to this tutorial. In the meantime, here are some links to additional resources on unit testing:

Tutorial Introduction Previous: Initial Setup

If you find this article helpful, please make a donation.

2 Comments on “Java Unit Testing Tutorial: Write Your First Unit Test”

  1. Anonymous says:

    typical example of how a junit should not be written:
    * setup should be within a @Before annotated method
    * method name should indicate the expected result for which input, and should be expressed within business terms

  2. @Anonymous, I agree that the method name could be a lot better. However, this is a tutorial aimed at complete beginners to testing, so I deliberately kept the example as simple as possible by including all the test code within the single test method. The logical progression from this example is to move on to a second test method, and then show how the common setup can be moved to the shared setUp method.

«    »