Close

JUnit 5 - @Tag Composition By Creating Custom Tag Annotations

[Last Updated: Dec 15, 2025]

What Is Tag Composition?

Creating a custom annotation that aggregates one or more @Tag annotations (and optionally other JUnit meta-annotations), so we can apply a meaningful, reusable label to tests.

While @Tag annotations work well, creating custom composed annotations can improve consistency and reduce repetition in large number of tests.
These custom annotations combine multiple tags or add semantic meaning to our tagging strategy.

Instead of repeatedly writing:

@Tag("integration")
@Tag("calc")
@Tag("database")
void myTest(){
 .....
}

We can write:

@IntegrationTest
void myTest(){
 .....
}

where

@Target({ TYPE, METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("integration")
@Tag("calc")
@Tag("database")
public @interface IntegrationTest {
}

Example

Defining custom annotation

package com.logicbig.example;

import org.junit.jupiter.api.Tag;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Tag("integration")
@Tag("database")
public @interface DatabaseIntegrationTest {}

As seen above, other than @Tag we also used @Timeout as well. It's a good idea to combine other annotations with @Tag annotation (e.g. @EnabledOnOs, @TestInstance etc) to avoid duplication across test classes.

Our Tests

package com.logicbig.example;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;

class CustomTagTest {

    @Test
    @DatabaseIntegrationTest
    void testDatabaseConnection() {
        // Implicitly has: @Tag("integration"),
        // @Tag("database"), @Timeout(2s)
        assertTrue(connectToDatabase());
    }

    @Test
    @DatabaseIntegrationTest
    @Tag("performance")
        // Can combine with additional tags
    void testQueryPerformance() {
        // Has: integration, database, performance tags + 2s timeout
        assertTrue(queryIsFast());
    }

    @Test
    void calcTest() {
        assertTrue(true);
    }

    private boolean connectToDatabase() {
        return true;
    }

    private boolean queryIsFast() {
        return true;
    }
}

Run Only Database Integration Tests

$ mvn test -Dgroups="integration & database"
[INFO] Scanning for projects...
[INFO]
[INFO] --------< com.logicbig.example:junit-5-custom-tag-annotations >---------
[INFO] Building junit-5-custom-tag-annotations 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-custom-tag-annotations ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-tagging-and-filtering\junit-5-custom-tag-annotations\src\main\resources
[INFO]
[INFO] --- compiler:3.11.0:compile (default-compile) @ junit-5-custom-tag-annotations ---
[INFO] No sources to compile
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-custom-tag-annotations ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-tagging-and-filtering\junit-5-custom-tag-annotations\src\test\resources
[INFO]
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ junit-5-custom-tag-annotations ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- surefire:3.5.0:test (default-test) @ junit-5-custom-tag-annotations ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] +--com.logicbig.example.CustomTagTest - 0.133 ss
[INFO] | +-- [OK] testDatabaseConnection - 0.081 ss
[INFO] | '-- [OK] testQueryPerformance - 0.011 ss
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.023 s
[INFO] Finished at: 2025-12-15T08:03:58+08:00
[INFO] ------------------------------------------------------------------------

Exclude Database Integration Tests

$ mvn test -DexcludedGroups="integration & database"
[INFO] Scanning for projects...
[INFO]
[INFO] --------< com.logicbig.example:junit-5-custom-tag-annotations >---------
[INFO] Building junit-5-custom-tag-annotations 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-custom-tag-annotations ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-tagging-and-filtering\junit-5-custom-tag-annotations\src\main\resources
[INFO]
[INFO] --- compiler:3.11.0:compile (default-compile) @ junit-5-custom-tag-annotations ---
[INFO] No sources to compile
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-custom-tag-annotations ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-tagging-and-filtering\junit-5-custom-tag-annotations\src\test\resources
[INFO]
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ junit-5-custom-tag-annotations ---
[INFO] Changes detected - recompiling the module! :source
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 2 source files with javac [debug target 17] to target\test-classes
[INFO]
[INFO] --- surefire:3.5.0:test (default-test) @ junit-5-custom-tag-annotations ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] +--com.logicbig.example.CustomTagTest - 0.064 ss
[INFO] | '-- [OK] calcTest - 0.041 ss
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.010 s
[INFO] Finished at: 2025-12-15T08:03:47+08:00
[INFO] ------------------------------------------------------------------------

Run Performance Database Tests

$ mvn test -Dgroups="integration & database & performance"
[INFO] Scanning for projects...
[INFO]
[INFO] --------< com.logicbig.example:junit-5-custom-tag-annotations >---------
[INFO] Building junit-5-custom-tag-annotations 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-custom-tag-annotations ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-tagging-and-filtering\junit-5-custom-tag-annotations\src\main\resources
[INFO]
[INFO] --- compiler:3.11.0:compile (default-compile) @ junit-5-custom-tag-annotations ---
[INFO] No sources to compile
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-custom-tag-annotations ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-tagging-and-filtering\junit-5-custom-tag-annotations\src\test\resources
[INFO]
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ junit-5-custom-tag-annotations ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- surefire:3.5.0:test (default-test) @ junit-5-custom-tag-annotations ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] +--com.logicbig.example.CustomTagTest - 0.071 ss
[INFO] | '-- [OK] testQueryPerformance - 0.044 ss
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.166 s
[INFO] Finished at: 2025-12-15T08:05:26+08:00
[INFO] ------------------------------------------------------------------------

Database Tests But Not Performance

$ mvn test -Dgroups="(integration & database) & !performance"
[INFO] Scanning for projects...
[INFO]
[INFO] --------< com.logicbig.example:junit-5-custom-tag-annotations >---------
[INFO] Building junit-5-custom-tag-annotations 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-custom-tag-annotations ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-tagging-and-filtering\junit-5-custom-tag-annotations\src\main\resources
[INFO]
[INFO] --- compiler:3.11.0:compile (default-compile) @ junit-5-custom-tag-annotations ---
[INFO] No sources to compile
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-custom-tag-annotations ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-tagging-and-filtering\junit-5-custom-tag-annotations\src\test\resources
[INFO]
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ junit-5-custom-tag-annotations ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- surefire:3.5.0:test (default-test) @ junit-5-custom-tag-annotations ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] +--com.logicbig.example.CustomTagTest - 0.072 ss
[INFO] | '-- [OK] testDatabaseConnection - 0.043 ss
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.292 s
[INFO] Finished at: 2025-12-15T08:07:13+08:00
[INFO] ------------------------------------------------------------------------

Example Project

Dependencies and Technologies Used:

  • junit-jupiter-engine 6.0.1 (Module "junit-jupiter-engine" of JUnit)
     Version Compatibility: 5.0.0 - 6.0.1Version List
    ×

    Version compatibilities of junit-jupiter-engine with this example:

    • 5.0.0
    • 5.0.1
    • 5.0.2
    • 5.0.3
    • 5.1.0
    • 5.1.1
    • 5.2.0
    • 5.3.0
    • 5.3.1
    • 5.3.2
    • 5.4.0
    • 5.4.1
    • 5.4.2
    • 5.5.0
    • 5.5.1
    • 5.5.2
    • 5.6.0
    • 5.6.1
    • 5.6.2
    • 5.6.3
    • 5.7.0
    • 5.7.1
    • 5.7.2
    • 5.8.0
    • 5.8.1
    • 5.8.2
    • 5.9.0
    • 5.9.1
    • 5.9.2
    • 5.9.3
    • 5.10.0
    • 5.10.1
    • 5.10.2
    • 5.10.3
    • 5.10.4
    • 5.10.5
    • 5.11.0
    • 5.11.1
    • 5.11.2
    • 5.11.3
    • 5.11.4
    • 5.12.0
    • 5.12.1
    • 5.12.2
    • 5.13.0
    • 5.13.1
    • 5.13.2
    • 5.13.3
    • 5.13.4
    • 5.14.0
    • 5.14.1
    • 6.0.0
    • 6.0.1

    Versions in green have been tested.

  • JDK 25
  • Maven 3.9.11

JUnit 5 - Custom Tag Annotations Select All Download
  • junit-5-custom-tag-annotations
    • src
      • test
        • java
          • com
            • logicbig
              • example
                • DatabaseIntegrationTest.java

    See Also