Introduction to JUnit 5 Tags

This is a free sample lesson of my Introduction to JUnit 5 course. My JUnit 5 course has 24 lessons, 47 exercises, and 13 quizzes which help you to work smarter and save time when you are writing tests with JUnit 5.

After you have finished this lesson, you:

  • Understand how JUnit 5 tags work.
  • Can add JUnit 5 tags to your test methods.
  • Know how you can make your tests easier to write and maintain by using custom annotations.

Let's begin.

Tagging Test Methods With JUnit 5

JUnit 5 tags allow you to divide your test methods into different groups and configure the groups whose tests are run when you run your tests. When you want to add a tag to a test class or a test method, you have to annotate your test class or test method with the @Tag annotation and configure the name of your tag by setting the value of the @Tag annotation's value attribute.

When you configure the name of your tag, you must use a non-null value that isn't blank. Also, when JUnit 5 validates the name of your tag, it removes the leading and trailing whitespace characters from it and ensures that the remaining name doesn't:

  • Contain whitespace characters.
  • Contain ISO controller characters.
  • Contain any reserved characters.
If you need more information about the syntax rules concerning JUnit 5 tags, you should take a look at the JUnit 5 User Guide.

Additional Reading:

When you annotate a test class with the @Tag annotation, Junit 5 has to decide which test methods get the given tag. JUnit 5 finds these test methods by following these steps:

First, JUnit 5 transforms the class hierarchy of your test class into a tree. The annotated test class is the root node of the created tree and the nested test classes which are enclosed by the annotated test class are added to the created tree as nodes.

The following figures illustrate the structure of two imaginary trees:

Example 1: The @Tag Annotation Is Added to a Test Class

Class hierarchy as a tree when the @Tag annotation is added to a test class

Example 2: The @Tag Annotation Is Added to a Nested Test Class

Class hierarchy as a tree when the @Tag annotation is added to a test class

Second, JUnit 5 finds all paths from the root node (aka the annotated test class) to the leaf nodes. A leaf node is either a "normal" test class or a nested test class which don't contain any nested test classes.

The following figure illustrates the paths found from the tree illustrated by the example 1:

All paths found from the class tree illustrated by the example 1

Third, JUnit 5 iterates the found paths one by one and processes all test classes found from the inspected path by following these steps:

  1. Find the test methods of the inspected class.
  2. Iterate the found test methods one by one.
  3. If the test method doesn't have the specified tag, add the tag to the inspected test method.

Next, we will take look at some examples which demonstrate how you can add one tag to your test methods.

Adding One Tag to Your Test Methods

When you want to add one tag to your test methods, you can use one of these three options:

First, if you want to add a tag to all test methods found from your test class, you have to annotate your test class with the @Tag annotation. For example, let's assume that you want to add the tag 'A' to all test methods found from your test class.

After you have done this, the source code of your test class looks as follows:

import org.junit.jupiter.api.Tag;

@Tag("A")
class RootClassTagAExampleTest {

}

Second, if you want to add a tag to all test methods found from a nested test class, you have to annotate your nested test class with the @Tag annotation. For example, let's assume that your test class has two nested test classes and you want that:

  • The test methods found from the WhenTestHasTagA class have the tag 'A'.
  • The test methods found from the WhenTestHasTagB class have the tag 'B'.

After you have the made required changes to your test class, its source code looks as follows:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Tag;

class NestedClassTagExampleTest {

    @Nested
    @DisplayName("When the test has the tag: A")
    @Tag("A")
    class WhenTestHasTagA {

    }

    @Nested
    @DisplayName("When the test has the tag: B")
    @Tag("B")
    class WhenTestHasTagB {

    }
}

Third, if you want to add a tag to one test method, you have to annotate your test method with the @Tag annotation. For example, let's assume that your test class has two test methods and you want add different tags ('A' and 'B') to these test methods.

After you have made the required changes to your test class, its source code looks as follows:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

class RootClassMethodTagExampleTest {

    @Test
    @DisplayName("Should be invoked when we run tests which have the tag: A")
    @Tag("A")
    void shouldBeInvokedInvokedWhenWeRunTestsWhichHaveTagA() {

    }

    @Test
    @DisplayName("Should be invoked when we run tests which have the tag: B")
    @Tag("B")
    void shouldBeInvokedInvokedWhenWeRunTestsWhichHaveTagB() {

    }
}

Let's move on and find out how you can add multiple tags to your test methods.

Adding Multiple Tags to Your Test Methods

If you want to add multiple tags to your test methods, you can use one of these two options:

First, because the @Tag annotation is a repeatable annotation, you can simple apply multiple @Tag annotations to your test class, nested test class, or test method. For example, let's assume that you want to add the tags 'A' and 'B' to all test methods found from your test class.

After you have made the required changes to your test class, its source code looks as follows:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Tag("A")
@Tag("B")
class RootClassMultipleTagsExampleTest {

}

Second, you can annotate your test class, nested test class, or test method with the @Tags annotation and configure the tags by setting the value of the @Tags annotation's value attribute. For example, let's assume that you want to add the tags 'A' and 'B' to all test methods found from your test class.

After you have made the required changes to your test class, its source code looks as follows:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Tags;
import org.junit.jupiter.api.Test;

@Tags({
        @Tag("A"), 
        @Tag("B")
})
class RootClassMultipleTagsExampleTest {

}

Next, you will find out how you can make your tests easier to write and maintain when you are adding tags to your test methods.

Writing a Custom Annotation

When you add tags to your test methods, you must specify the names of your tags by using string literals. Because it's very likely that you want to add the same tag to test methods which are found from different test classes, you must write the same name multiple times. This is a problem because:

  • You have to remember the correct spelling of your tag's name and double-check that the name of your tag doesn't contain any typos. This makes your tests hard to write.
  • If you want to change the name of your tag, you have to make that change to every test class which contains the updated tag. This makes your tests hard to maintain.

It's clear that you should remove duplicate tag names from your test suite. You can get rid of duplicate tag names by writing a custom annotation which adds the required tag to your test methods.

You can also declare constants which contain your tag names and use these constants together with the @Tag annotation. However, I think that using custom annotations is a better choice because they make your test code a bit easier to read.

Let's assume that you want to write a custom annotation which adds the tag 'unitTest' to your test methods. You can write this annotation by following these steps:

  1. Create a new annotation class.
  2. Ensure that you can annotate both test classes and test methods with your new annotation.
  3. Ensure that your annotation is recorded in the class file by the compiler and retained by the VM at runtime.
  4. Ensure that your custom annotation is part of the public contract of the annotated element.
  5. Ensure that you can add the tag 'unitTest' to your test methods by using your new annotation.

After you have written your custom annotation, its source code looks as follows:

import org.junit.jupiter.api.Tag;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Tag("unitTest")
public @interface UnitTest {
}

You can now add the tag 'unitTest' to your test methods by annotating your test classes and test methods with the @UnitTest annotation. For example, let's assume that you want to add the tag 'unitTest' to all test methods found from your test class.

After you have made the required changes to your test class, its source code looks as follows:

@UnitTest
class UnitTestAnnotationExampleTest {

}

As you can see, if you replace the @Tag annotation with a custom annotation, you will make your life easier because:

  • You don't have to remember the correct spelling of your tag's name and you cannot make any typos when you add this tag to your test methods.
  • If you want to change the name of your tag, you have to make that change to only one place.

You can now divide your test methods into groups by using JUnit 5 tags. Let's summarize what you learned from this lesson.

This is a free sample lesson of my Introduction to JUnit 5 course. My JUnit 5 course has 24 lessons, 47 exercises, and 13 quizzes which help you to work smarter and save time when you are writing tests with JUnit 5.

Summary

This lesson has taught you six things:

  • JUnit 5 tags allow you to divide your test methods into different groups and configure the groups whose tests are run when you run your tests.
  • If you want to add a tag to all test methods found from your test class, you have to annotate your test class with the @Tag annotation.
  • If you want to add a tag to all test methods found from a nested test class, you have to annotate your nested test class with the @Tag annotation.
  • If you want to add a tag to one test method, you have to annotate your test method with the @Tag annotation.
  • If you want to add multiple tags to your test methods, you can use multiple @Tag annotations or use the @Tags annotation.
  • If you want to make your tests easier to write and maintain, you must replace the @Tag annotation with a custom annotation.

Get the sample code from Github

0 comments… add one

Leave a Reply