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.
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 theBlockJUnit4ClassRunner
. - 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’svalue
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’svalue
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’svalue
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’svalue
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’svalue
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.