Selecting tests by tags and classes in JUnit - Build an Automation Script
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.discovery.ClassSelector; import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.engine.discovery.TagFilter; import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.LauncherDiscoveryRequestBuilder; import org.junit.platform.launcher.LauncherFactory; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.TestPlan; import org.junit.platform.launcher.listeners.SummaryGeneratingListener; import static org.junit.jupiter.api.Assertions.assertTrue; public class TestFilterByTagAndClass { @Tag("fast") public static class FastTests { @Test void fastTest1() { assertTrue(true); } } @Tag("database") public static class DatabaseTests { @Test void databaseTest1() { assertTrue(true); } } public static class UserServiceTest { @Test void userServiceTest1() { assertTrue(true); } } public static void main(String[] args) { runTestsByTag("fast"); runTestsByClass(UserServiceTest.class); } private static void runTestsByTag(String tag) { LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request() .filters(TagFilter.includeTags(tag)) .build(); Launcher launcher = LauncherFactory.create(); SummaryGeneratingListener listener = new SummaryGeneratingListener(); launcher.registerTestExecutionListeners(listener); launcher.execute(request); long testsFound = listener.getSummary().getTestsFoundCount(); long testsSucceeded = listener.getSummary().getTestsSucceededCount(); System.out.println("Tests run with tag '" + tag + "': " + testsFound); assertTrue(testsFound > 0, "No tests found with tag '" + tag + "'"); assertTrue(testsFound == testsSucceeded, "Some tests with tag '" + tag + "' failed"); } private static void runTestsByClass(Class<?> testClass) { LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request() .selectors(DiscoverySelectors.selectClass(testClass)) .build(); Launcher launcher = LauncherFactory.create(); SummaryGeneratingListener listener = new SummaryGeneratingListener(); launcher.registerTestExecutionListeners(listener); launcher.execute(request); long testsFound = listener.getSummary().getTestsFoundCount(); long testsSucceeded = listener.getSummary().getTestsSucceededCount(); System.out.println("Tests run from class '" + testClass.getSimpleName() + "': " + testsFound); assertTrue(testsFound > 0, "No tests found in class '" + testClass.getSimpleName() + "'"); assertTrue(testsFound == testsSucceeded, "Some tests in class '" + testClass.getSimpleName() + "' failed"); } }
This code defines three test classes with different tags and one without tags.
The runTestsByTag method builds a test request filtered by the given tag using TagFilter.includeTags. It runs the tests and asserts that some tests were found and all passed.
The runTestsByClass method builds a test request selecting only the specified test class. It runs the tests and asserts that some tests were found and all passed.
Using the JUnit Platform Launcher API allows us to programmatically select tests by tag or class, which is useful for automation and custom test runners.
Now add data-driven testing with 3 different tag filters: 'fast', 'database', and 'slow'. Run tests for each tag and verify results.
Practice
@Tag in JUnit tests?Solution
Step 1: Understand the role of @Tag annotation
The@Tagannotation is used to label tests with a category or group name.Step 2: Identify the benefit of tagging tests
Tagging allows you to select and run only tests with specific tags, making test runs focused and faster.Final Answer:
To group tests so you can run specific sets easily -> Option BQuick Check:
Tags group tests for selective runs [OK]
- Thinking @Tag changes test order
- Believing @Tag skips tests permanently
- Assuming @Tag renames test methods
Solution
Step 1: Recall correct annotation syntax in Java
Annotations use the format@AnnotationName("value")with parentheses and quotes for string values.Step 2: Match the correct syntax for @Tag
@Tag("fast") public void testMethod() {} uses@Tag("fast")correctly before the method declaration.Final Answer:
@Tag("fast") public void testMethod() {} -> Option AQuick Check:
Annotation syntax = @Tag("value") [OK]
- Omitting parentheses around tag value
- Missing quotes around the tag string
- Using colon or equals instead of parentheses
--include-tag fast?
@Tag("slow")
class ExampleTests {
@Test
void testA() {}
@Test
@Tag("fast")
void testB() {}
@Test
@Tag("fast")
void testC() {}
}Solution
Step 1: Understand tag filtering behavior
When running with--include-tag fast, only tests tagged with "fast" run.Step 2: Analyze tags on each test
Class has @Tag("slow"), so by default tests inherit "slow" tag. testA has no method tag, so only "slow" applies. testB and testC have @Tag("fast") overriding or adding to tags.Step 3: Determine which tests match "fast" tag
Only testB and testC have the "fast" tag, so only these run.Final Answer:
Only testB and testC -> Option CQuick Check:
Include tag "fast" runs only tests tagged "fast" [OK]
- Assuming class tag applies to all tests ignoring method tags
- Thinking all tests run without tag filtering
- Confusing include and exclude tag filters
LoginTests but your command mvn test -Dgroups=LoginTests runs no tests. What is the likely problem?Solution
Step 1: Understand Maven test filtering options
Maven Surefire plugin uses-Dtest=ClassNameto run tests by class name, not-Dgroups.Step 2: Identify correct command to run tests by class
To run tests fromLoginTests, usemvn test -Dtest=LoginTests.Final Answer:
The command should bemvn test -Dtest=LoginTeststo run by class -> Option AQuick Check:
Run by class uses -Dtest=ClassName [OK]
- Using -Dgroups which is for TestNG, not JUnit
- Assuming class names are lowercase
- Expecting @Group annotation in JUnit
FastTests tagged with @Tag("fast") and SlowTests tagged with @Tag("slow"). You want to run all tests except those tagged "slow" and only from classes whose names end with "Tests". Which command correctly runs this selection?Solution
Step 1: Understand tag and class name filters
To exclude slow tests, use--exclude-tag slow. To include only classes ending with "Tests", use--include-classname .*Testsregex.Step 2: Analyze each option
junit-platform-console --exclude-tag slow --include-classname .*Tests excludes slow tags and includes classes matching .*Tests, which matches both FastTests and SlowTests classes but excludes slow-tagged tests.Step 3: Confirm correct filtering
junit-platform-console --include-tag fast --include-classname .*Tests includes only fast tags, which works but excludes any untagged tests. junit-platform-console --exclude-tag slow --exclude-classname .*Tests excludes classes ending with Tests, which is opposite of requirement. junit-platform-console --include-tag slow --include-classname FastTests includes slow tags, which is opposite of requirement.Final Answer:
junit-platform-console --exclude-tag slow --include-classname .*Tests -> Option DQuick Check:
Exclude slow tag + include class regex = junit-platform-console --exclude-tag slow --include-classname .*Tests [OK]
- Using include-tag slow instead of exclude-tag
- Excluding classes instead of including
- Confusing include-tag and exclude-tag usage
Ready to prove it?
Pass the test and this pattern moves unknown
