Introduction to JUnit 4 Test Runners

After we have finished this lesson, we:

  • Understand the responsibilities of a JUnit 4 test runner.
  • Can use a non-default test runner.
  • Can create a test suite by using the Categories test runner.
This lesson assumes that:

Get the source code from Github.

What Is a Test Runner?

A test runner instantiates our test classes, runs the test methods found from these classes, and reports the test results. We will use a few different test runners during this course, but at the moment we have to only know that:

  • All test runners must extend the abstract org.junit.runner.Runner class.
  • We can use a custom test runner by annotating our test class with the @RunWith annotation. If a test class doesn’t have this annotation, JUnit 4 runs it by using the default test runner that is called the BlockJUnit4ClassRunner.
  • A test class can use only test runner.

We are now familiar with the basics. Let’s find out how we can run our tests by using a “custom” test runner.

Using a Non-Default Test Runner

If we want to use a custom test runner, we have to annotate our test class with the @RunWith annotation and set the type of the test runner as the value of the @RunWith annotation’s value attribute.

For example, if we want to run the test methods of the FooBarTest class by using the CustomRunner class, the source code of the FooBarTest class must look as follows:

@RunWith(CustomRunner.class)
public FooBarTest {
}

Next, we will use this information and create a test suite by using the Categories test runner.

Creating a Test Suite With the Categories Test Runner

The simplest way to create a test suite is to use the Suite test runner. This test runner runs all tests found from the test classes which belong to the created test suite. However, if we have to include test methods in our test suite and/or exclude test methods from it, we cannot use the Suite test runner. Luckily, the Categories test runner provides these features for us.

Let’s find out how we can create a test suite by using the Categories test runner.

Creating the Marker Interfaces

The first thing that we have to do is to create the marker interfaces which are used to specify the category of a test class or a test method. Let’s create two marker interfaces: CategoryA and CategoryB.

The source code of these marker interfaces looks as follows:

public interface CategoryA {
}

public interface CategoryB {
}

After we have created the required marker interfaces, we have to write our test classes and configure the categories of our test methods.

Writing Our Test Classes

We can configure the categories of our test methods by using the @Category annotation. When we use the @Category annotation, we have to follow these rules:

  • If we want to add all test methods found from a test class to a specific category, we have to annotate our test class with the @Category annotation and set the type of the marker interface as the value of @Category annotation’s value attribute.
  • If we want to add a test method to a specific category, we have to annotate our test method with the @Category annotation and set the type of the marker interface as the value of @Category annotation’s value attribute.

Let’s create two test classes:

First, the ATest class contains one test method called testA(). This method simply prints the string: ‘This test belongs to the category A’ to System.out. Naturally, all test methods found from this class belong to the CategoryA.

The source code of the ATest class looks as follows:

import org.junit.Test;
import org.junit.experimental.categories.Category;

@Category(CategoryA.class)
public class ATest {

    @Test
    public void testA() {
        System.out.println("This test belongs to the category A");
    }
}

Second, the BTest class contains one test method called testB() that prints the string: ‘This test belongs to the category B’ to System.out. All test methods found from this class belong to the CategoryB.

The source code of the BTest class looks as follows:

import org.junit.Test;
import org.junit.experimental.categories.Category;

@Category(CategoryB.class)
public class BTest {

    @Test
    public void testB() {
        System.out.println("This test belongs to the category B");
    }
}

We have now created our test classes. Let’s find out how we can create the test suites which run our test methods.

Creating Our Test Suites

We can create a test suite, which uses the Categories test runner, by following these steps:

First, we have to create a public class and ensure that all tests of our test suite are run by the Categories test runner.

Second, we have to configure the included and/or excluded test categories by following these rules:

  • We can include test categories by annotating the created class with the @IncludeCategory annotation and setting the types of the included categories as the value of the @IncludeCategory annotation’s value attribute.
  • We can exclude test categories by annotating the created class with the @ExcludeCategory annotation and setting the types of the excluded categories as the value of the @ExcludeCategory annotation’s value attribute.

Third, we have to configure the test classes of our test suite. We can do this by annotating the created class with the @SuiteClasses annotation and setting the types of the test classes as the value of the @SuiteClasses annotation’s value attribute.

Let’s create two test suites that consist of the ATest and BTest classes:

First, the ATestSuite class specifies a test suite which includes all test methods which belong to the CategoryA.

The source code of the ATestSuite class looks as follows:

import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.experimental.categories.Categories.IncludeCategory;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Categories.class)
@IncludeCategory(CategoryA.class)
@SuiteClasses({ATest.class, BTest.class})
public class ATestSuite {
}

Second, the BTestSuite class specifies a test suite that includes all test methods which belong to the CategoryB.

The source code of the BTestSuite class looks as follows:

import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.experimental.categories.Categories.IncludeCategory;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Categories.class)
@IncludeCategory(CategoryB.class)
@SuiteClasses({ATest.class, BTest.class})
public class BTestSuite {
}

We have now created our test suites. Let’s see what happens when we run them.

Running Our Test Suites

When we run the ATestSuite class, the following line is written to System.out:

This test belongs to the category A

On other hand, when we run the BTestSuite class, we see that the following line is written to System.out:

This test belongs to the category B

In other words, we have successfully created two test suites by using the Categories test runner.

Let’s summarize what what we learned from this lesson.

Summary

This lesson taught us four things:

  • A test runner instantiates our test classes, runs the test methods found from these classes, and reports the test results.
  • We can specify the used test runner by annotating a test class with the @RunWith annotation and setting the type of the test runner as the value of the @RunWith annotation’s value attribute.
  • A test class can use only one test runner.
  • The Categories test runner gives us the possibility to include test methods in our test suite and/or exclude test methods from it.

Get the source code from Github.