CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-junit--junit

JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.

Overview
Eval results
Files

categories.mddocs/

Categories

Categories is an experimental feature for grouping and filtering tests using marker interfaces. It allows selective test execution based on category annotations, useful for organizing tests by type (unit, integration, performance) or other criteria.

Capabilities

Category Annotation

Marks tests or test classes as belonging to one or more categories. Categories are defined as marker interfaces.

/**
 * Marks a test method or class as belonging to categories
 * @param value - Category interface(s) this test belongs to
 */
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@ValidateWith(CategoryValidator.class)
public @interface Category {
    Class<?>[] value();
}

Usage Examples:

import org.junit.Test;
import org.junit.experimental.categories.Category;
import static org.junit.Assert.*;

// Define category marker interfaces
public interface SlowTests {}
public interface FastTests {}
public interface IntegrationTests {}
public interface UnitTests {}

// Categorize entire test class
@Category(UnitTests.class)
public class CalculatorTest {
    @Test
    public void testAddition() {
        assertEquals(5, 2 + 3);
    }

    @Test
    @Category(SlowTests.class)
    public void testComplexCalculation() {
        // This test is both UnitTests and SlowTests
        performExpensiveCalculation();
    }
}

// Multiple categories
@Category({IntegrationTests.class, SlowTests.class})
public class DatabaseTest {
    @Test
    public void testConnection() {
        // Integration and slow test
        connectToDatabase();
    }

    @Test
    @Category(FastTests.class)
    public void testConfiguration() {
        // Override: this is fast despite class being slow
        checkConfig();
    }
}

// Method-level categories
public class MixedTest {
    @Test
    @Category(FastTests.class)
    public void fastTest() {
        assertTrue(true);
    }

    @Test
    @Category(SlowTests.class)
    public void slowTest() {
        Thread.sleep(1000);
    }

    @Test
    @Category({IntegrationTests.class, SlowTests.class})
    public void integrationTest() {
        testExternalSystem();
    }
}

Categories Runner

Special suite runner that filters tests based on included and excluded categories.

/**
 * Suite runner that filters tests by category
 * Only runs tests matching category criteria
 */
@RunWith(Suite.class)
public class Categories extends Suite {
    /**
     * Creates Categories runner
     * @param klass - Suite class
     * @param builder - Runner builder
     * @throws InitializationError if initialization fails
     */
    public Categories(Class<?> klass, RunnerBuilder builder) throws InitializationError;

    /**
     * Specify categories to include
     * Only tests with these categories will run
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface IncludeCategory {
        /**
         * Categories to include
         */
        Class<?>[] value() default {};

        /**
         * If true, runs tests annotated with any of the categories
         * Otherwise, runs tests only if annotated with all categories
         */
        boolean matchAny() default true;
    }

    /**
     * Specify categories to exclude
     * Tests with these categories will not run
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface ExcludeCategory {
        /**
         * Categories to exclude
         */
        Class<?>[] value() default {};

        /**
         * If true, excludes tests annotated with any of the categories
         * Otherwise, excludes tests only if annotated with all categories
         */
        boolean matchAny() default true;
    }
}

Usage Examples:

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

// Run only fast tests
@RunWith(Categories.class)
@IncludeCategory(FastTests.class)
@SuiteClasses({
    CalculatorTest.class,
    StringUtilsTest.class,
    DateUtilsTest.class,
    DatabaseTest.class
})
public class FastTestSuite {
    // Only tests marked with @Category(FastTests.class) will run
}

// Run all except slow tests
@RunWith(Categories.class)
@ExcludeCategory(SlowTests.class)
@SuiteClasses({
    CalculatorTest.class,
    DatabaseTest.class,
    NetworkTest.class
})
public class QuickTestSuite {
    // All tests except those marked @Category(SlowTests.class)
}

// Run integration tests only
@RunWith(Categories.class)
@IncludeCategory(IntegrationTests.class)
@SuiteClasses({
    DatabaseTest.class,
    ApiTest.class,
    NetworkTest.class,
    FileSystemTest.class
})
public class IntegrationTestSuite {
}

// Include and exclude together
@RunWith(Categories.class)
@IncludeCategory(IntegrationTests.class)
@ExcludeCategory(SlowTests.class)
@SuiteClasses({
    DatabaseTest.class,
    ApiTest.class,
    NetworkTest.class
})
public class FastIntegrationSuite {
    // Only fast integration tests
}

CategoryFilter

Programmatic filtering of tests by category. Used for custom test execution.

/**
 * Filter for selecting tests by category
 */
public class CategoryFilter extends Filter {
    /**
     * Create filter that includes only matching categories
     * @param categoryType - Category to include
     * @return CategoryFilter
     */
    public static CategoryFilter include(Class<?> categoryType);

    /**
     * Create filter that includes only matching categories
     * @param includes - Categories to include
     * @return CategoryFilter
     */
    public static CategoryFilter include(Class<?>... includes);

    /**
     * Create filter that excludes matching categories
     * @param categoryType - Category to exclude
     * @return CategoryFilter
     */
    public static CategoryFilter exclude(Class<?> categoryType);

    /**
     * Create filter that excludes matching categories
     * @param excludes - Categories to exclude
     * @return CategoryFilter
     */
    public static CategoryFilter exclude(Class<?>... excludes);

    /**
     * Create filter with include and exclude rules
     * @param matchAnyInclusions - Whether to match any (true) or all (false) inclusion categories
     * @param inclusions - Set of categories to include
     * @param matchAnyExclusions - Whether to match any (true) or all (false) exclusion categories
     * @param exclusions - Set of categories to exclude
     * @return CategoryFilter
     */
    public static CategoryFilter categoryFilter(
        boolean matchAnyInclusions,
        Set<Class<?>> inclusions,
        boolean matchAnyExclusions,
        Set<Class<?>> exclusions
    );

    /**
     * Check if test should run
     * @param description - Test description
     * @return true if test should run
     */
    public boolean shouldRun(Description description);

    /**
     * Get filter description
     * @return Description string
     */
    public String describe();
}

Usage Examples:

import org.junit.experimental.categories.CategoryFilter;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;
import java.util.Set;
import java.util.HashSet;

public class CategoryRunner {
    public static void main(String[] args) {
        // Run only fast tests
        Request request = Request.aClass(AllTests.class);
        request = request.filterWith(CategoryFilter.include(FastTests.class));
        Result result = new JUnitCore().run(request);

        // Run all except slow tests
        Request request2 = Request.aClass(AllTests.class);
        request2 = request2.filterWith(CategoryFilter.exclude(SlowTests.class));
        Result result2 = new JUnitCore().run(request2);

        // Complex filtering with categoryFilter
        Set<Class<?>> inclusions = new HashSet<>();
        inclusions.add(IntegrationTests.class);
        Set<Class<?>> exclusions = new HashSet<>();
        exclusions.add(SlowTests.class);

        CategoryFilter filter = CategoryFilter.categoryFilter(
            true,        // Match any inclusion category
            inclusions,  // Include integration tests
            true,        // Match any exclusion category
            exclusions   // Exclude slow tests
        );
        Request request3 = Request.aClass(AllTests.class);
        request3 = request3.filterWith(filter);
        Result result3 = new JUnitCore().run(request3);
    }
}

// Custom test runner with categories
public class CustomCategoryRunner {
    public static Result runCategories(Class<?> testClass, Class<?>... categories) {
        Request request = Request.aClass(testClass);
        request = request.filterWith(CategoryFilter.include(categories));
        return new JUnitCore().run(request);
    }

    public static void main(String[] args) {
        // Run specific categories
        Result result = runCategories(
            MyTestSuite.class,
            FastTests.class,
            UnitTests.class
        );
        System.out.println("Tests run: " + result.getRunCount());
    }
}

Common Category Patterns

Test Type Categories

Organize tests by their nature and scope.

// Marker interfaces for test types
public interface UnitTests {}
public interface IntegrationTests {}
public interface EndToEndTests {}
public interface PerformanceTests {}
public interface SecurityTests {}

@Category(UnitTests.class)
public class BusinessLogicTest {
    @Test
    public void testCalculation() {
        // Pure unit test
    }
}

@Category(IntegrationTests.class)
public class DatabaseIntegrationTest {
    @Test
    public void testDatabaseQuery() {
        // Tests with database
    }
}

@Category(EndToEndTests.class)
public class UserFlowTest {
    @Test
    public void testCompleteUserJourney() {
        // Full system test
    }
}

Speed Categories

Group tests by execution time for quick feedback loops.

public interface FastTests {}      // < 100ms
public interface MediumTests {}    // 100ms - 1s
public interface SlowTests {}      // > 1s

@Category(FastTests.class)
public class QuickUnitTest {
    @Test
    public void instantTest() {
        assertEquals(4, 2 + 2);
    }
}

@Category(SlowTests.class)
public class HeavyIntegrationTest {
    @Test
    public void testLargeDataset() {
        processMillionRecords();
    }
}

Environment Categories

Tests that require specific environments or resources.

public interface RequiresDatabase {}
public interface RequiresNetwork {}
public interface RequiresDocker {}
public interface RequiresLinux {}
public interface RequiresWindows {}

@Category(RequiresDatabase.class)
public class DatabaseTest {
    @Test
    public void testQuery() {
        // Needs database
    }
}

@Category({RequiresNetwork.class, RequiresDocker.class})
public class MicroserviceTest {
    @Test
    public void testServiceCommunication() {
        // Needs network and Docker
    }
}

Feature Categories

Organize by feature or module being tested.

public interface PaymentTests {}
public interface AuthenticationTests {}
public interface ReportingTests {}
public interface NotificationTests {}

@Category(PaymentTests.class)
public class PaymentProcessorTest {
    @Test
    public void testPayment() {
        processPayment();
    }
}

@Category(AuthenticationTests.class)
public class LoginTest {
    @Test
    public void testLogin() {
        authenticateUser();
    }
}

Build Pipeline Categories

Different category suites for different build stages.

// CI pipeline categories
public interface CommitTests {}     // Run on every commit
public interface NightlyTests {}    // Run nightly
public interface WeeklyTests {}     // Run weekly
public interface ManualTests {}     // Run manually only

// Commit stage - fast tests only
@RunWith(Categories.class)
@IncludeCategory(CommitTests.class)
@SuiteClasses({/* all test classes */})
public class CommitStageSuite {}

// Nightly build - all automated tests
@RunWith(Categories.class)
@ExcludeCategory(ManualTests.class)
@SuiteClasses({/* all test classes */})
public class NightlyBuildSuite {}

// Usage in tests
@Category(CommitTests.class)
public class FastCoreTest {
    // Runs on every commit
}

@Category({NightlyTests.class, SlowTests.class})
public class ExtensiveTest {
    // Runs in nightly builds
}

Maven Integration

Run specific categories from Maven command line.

<!-- pom.xml configuration -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.2</version>
            <configuration>
                <groups>com.example.FastTests</groups>
                <excludedGroups>com.example.SlowTests</excludedGroups>
            </configuration>
        </plugin>
    </plugins>
</build>
# Run specific categories from command line
mvn test -Dgroups=com.example.FastTests
mvn test -DexcludedGroups=com.example.SlowTests
mvn test -Dgroups=com.example.UnitTests,com.example.FastTests

Gradle Integration

Run specific categories from Gradle.

// build.gradle configuration
test {
    useJUnit {
        includeCategories 'com.example.FastTests'
        excludeCategories 'com.example.SlowTests'
    }
}

// Custom test tasks for different categories
task fastTests(type: Test) {
    useJUnit {
        includeCategories 'com.example.FastTests'
    }
}

task integrationTests(type: Test) {
    useJUnit {
        includeCategories 'com.example.IntegrationTests'
    }
}
# Run specific test tasks
./gradlew fastTests
./gradlew integrationTests
./gradlew test # All tests

Types

/**
 * Base class for test filters
 */
public abstract class Filter {
    /**
     * Returns true if test should run
     * @param description - Test description
     * @return true to run test
     */
    public abstract boolean shouldRun(Description description);

    /**
     * Returns description of filter
     * @return Description string
     */
    public abstract String describe();

    /**
     * Compose filters with AND logic
     * @param second - Second filter
     * @return Combined filter
     */
    public Filter intersect(Filter second);

    /**
     * Create filter that matches anything
     * @return Filter that allows all tests
     */
    public static Filter matchAll();
}

/**
 * Factory for creating category filters from command line arguments
 */
public class CategoryFilterFactory implements FilterFactory {
    /**
     * Create filter from factory parameters
     * @param params - Filter parameters
     * @return CategoryFilter
     */
    public Filter createFilter(FilterFactoryParams params) throws FilterNotCreatedException;
}

/**
 * Validates Category annotations
 */
public class CategoryValidator implements AnnotationValidator {
    /**
     * Validate category annotations on test class
     * @param testClass - Test class to validate
     * @return List of validation errors
     */
    public List<Exception> validateAnnotatedClass(TestClass testClass);
}

Install with Tessl CLI

npx tessl i tessl/maven-junit--junit

docs

annotations.md

assertions.md

assumptions.md

categories.md

index.md

matchers.md

rules.md

standard-runners.md

test-runners.md

theories.md

tile.json