Skip to content

ImportOption.DoNotIncludeTests and ImportOption.OnlyIncludeTests don't detect tests in custom Gradle source sets #1578

@ajax-semenov-y

Description

@ajax-semenov-y

Problem

The ImportOption.Predefined.GRADLE_TEST_PATTERN in ArchUnit fails to detect tests located in custom Gradle source sets (e.g., integrationTest, functionalTest, etc.) because the pattern only matches lowercase test in the build path.

Current Implementation

From com.tngtech.archunit.core.importer.ImportOption$Predefined (line ~102):

static final PatternPredicate GRADLE_TEST_PATTERN =
    new PatternPredicate(".*/build/classes/([^/]+/)?test/.*");

This pattern matches paths like:

  • /build/classes/java/test/ (standard test source set)
  • /build/classes/kotlin/test/
  • /build/classes/java/integrationTest/ (custom source set)
  • /build/classes/kotlin/functionalTest/ (custom source set)
  • /build/classes/java/e2eTest/ (custom source set)

Impact

When using ImportOption.DoNotIncludeTests or ImportOption.OnlyIncludeTests:

  • Custom test source sets are not excluded when using DoNotIncludeTests
  • Custom test source sets are not included when using OnlyIncludeTests

This causes incorrect behavior when architectural rules should apply to or exclude tests from custom source sets.

Example Scenario

// Gradle configuration with custom source set
sourceSets {
    create("integrationTest") {
        compileClasspath += sourceSets.main.get().output
        runtimeClasspath += sourceSets.main.get().output
    }
}

// ArchUnit test that fails to recognize integrationTest classes as tests
@AnalyzeClasses(
    packages = "com.example",
    importOptions = [ImportOption.DoNotIncludeTests::class]
)
class ArchitectureTest {
    // This will incorrectly analyze integrationTest classes
    // because the pattern doesn't recognize them as tests
}

Proposed Solution

The pattern should be more flexible to match any path segment containing "test" (case-insensitive) or "Test" suffix:

Option 1: Case-insensitive matching

".*/build/classes/([^/]+/)?(?i).*test.*/.*"

Option 2: Match common test source set naming patterns

".*/build/classes/([^/]+/)?([a-z]+)?[Tt]est(s)?/.*"

This would match:

  • test (standard)
  • integrationTest
  • functionalTest
  • e2eTest
  • tests (plural variant)

Workaround

Currently, users must implement custom ImportOption for each custom test source set:

public class DoNotIncludeIntegrationTests implements ImportOption {
    private static final Pattern PATTERN =
        Pattern.compile(".*/build/classes/([^/]+/)?integrationTest/.*");

    @Override
    public boolean includes(Location location) {
        return !location.matches(PATTERN);
    }
}

Environment

  • ArchUnit version: 1.4.1
  • Build tool: Gradle
  • Custom source set name: integrationTest

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions