This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Configuration

Configure Verifyica for your testing needs

Verifyica provides flexible configuration options to control test execution, parallelism, filtering, and behavior.

Configuration Methods

Verifyica can be configured through:

  1. Properties File - verifyica.properties in the classpath
  2. System Properties - -D flags passed to the JVM
  3. Environment Variables - Environment variables with VERIFYICA_ prefix

Quick Configuration Topics

Properties

Configure engine behavior, parallelism, logging, and more through properties.

Learn more about Properties →

Filters

Use YAML-based filters to include or exclude tests by class name, package, or tags.

Learn more about Filters →

Parallelism

Control how many classes, arguments, and tests execute in parallel.

Learn more about Parallelism →

Configuration Priority

When the same property is defined in multiple places, the priority is:

  1. System Properties (highest priority)
  2. Environment Variables
  3. Properties File (lowest priority)

Example:

# Properties file: parallelism = 2
# System property overrides it
java -Dverifyica.engine.argument.parallelism=4 -jar test.jar

# Result: parallelism = 4

Configuration File Location

The verifyica.properties file should be placed in:

src/test/resources/verifyica.properties

Example verifyica.properties:

# Class-level parallelism
verifyica.engine.class.parallelism=4

# Argument-level parallelism
verifyica.engine.argument.parallelism=2

# Thread type (virtual, platform, platform-ephemeral)
verifyica.engine.thread.type=virtual

# Filter definitions file
verifyica.engine.filter.definitions.filename=verifyica.engine.filter.definitions.yaml

# Logger configuration
verifyica.engine.logger.level=INFO

Next Steps

1 - Properties

Complete reference for all Verifyica configuration properties

This page provides a complete reference for all Verifyica configuration properties.

Property Format

Properties can be set in three ways:

1. Properties File

Create src/test/resources/verifyica.properties:

verifyica.engine.argument.parallelism=4
verifyica.engine.thread.type=virtual

2. System Properties

Pass as JVM arguments:

java -Dverifyica.engine.argument.parallelism=4 -jar test.jar

3. Environment Variables

Set environment variables (replace . with _ and uppercase):

export VERIFYICA_ENGINE_ARGUMENT_PARALLELISM=4

Parallelism Properties

verifyica.engine.class.parallelism

Controls how many test classes execute in parallel.

  • Type: Integer
  • Default: 1 (sequential)
  • Example: verifyica.engine.class.parallelism=4

Usage:

# Run 4 test classes in parallel
verifyica.engine.class.parallelism=4

verifyica.engine.argument.parallelism

Controls how many arguments within a class execute in parallel.

  • Type: Integer
  • Default: 1 (sequential)
  • Example: verifyica.engine.argument.parallelism=2

Note: This is a default value. Individual @ArgumentSupplier annotations can override this:

@Verifyica.ArgumentSupplier(parallelism = 4)  // Overrides default
public static Collection<String> arguments() {
    return generateArguments();
}

Usage:

# Run 2 arguments in parallel by default
verifyica.engine.argument.parallelism=2

Thread Configuration

verifyica.engine.thread.type

Configures the type of threads used for parallel execution.

  • Type: String
  • Values: virtual, platform, platform-ephemeral
  • Default: platform
  • Example: verifyica.engine.thread.type=virtual

Options:

ValueDescriptionBest For
virtualJava 21+ virtual threadsHigh concurrency, I/O-bound tests
platformPlatform threads (traditional)CPU-bound tests, Java 8+
platform-ephemeralPlatform threads that are discarded after useTests with thread-local state

Usage:

# Use virtual threads (requires Java 21+)
verifyica.engine.thread.type=virtual

# Use platform threads (default)
verifyica.engine.thread.type=platform

# Use ephemeral platform threads
verifyica.engine.thread.type=platform-ephemeral

Virtual Threads Example:

Virtual threads are ideal for I/O-bound tests with high concurrency:

verifyica.engine.thread.type=virtual
verifyica.engine.argument.parallelism=100  # Can handle many more with virtual threads

State Machine Throttling

These properties control how fast state machines transition, useful for debugging.

verifyica.engine.class.state.machine.throttle

Throttle class-level state machine transitions.

  • Type: Two integers (min, max) in milliseconds
  • Default: 0, 1000
  • Example: verifyica.engine.class.state.machine.throttle=100, 500

verifyica.engine.argument.state.machine.throttle

Throttle argument-level state machine transitions.

  • Type: Two integers (min, max) in milliseconds
  • Default: 0, 1000
  • Example: verifyica.engine.argument.state.machine.throttle=100, 500

verifyica.engine.test.state.machine.throttle

Throttle test-level state machine transitions.

  • Type: Two integers (min, max) in milliseconds
  • Default: 0, 1000
  • Example: verifyica.engine.test.state.machine.throttle=100, 500

Usage:

Useful for debugging timing issues or simulating slow operations:

# Add random delay between 0-1000ms to state transitions
verifyica.engine.argument.state.machine.throttle=0, 1000

Logging Properties

verifyica.engine.logger.level

Sets the logging level for Verifyica’s internal logger.

  • Type: String
  • Values: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF
  • Default: INFO
  • Example: verifyica.engine.logger.level=DEBUG

Usage:

# Enable debug logging
verifyica.engine.logger.level=DEBUG

# Disable all logging
verifyica.engine.logger.level=OFF

# Only errors
verifyica.engine.logger.level=ERROR

verifyica.engine.logger.regex

Filter log messages by regex pattern.

  • Type: Regular expression
  • Default: (none - all messages logged)
  • Example: verifyica.engine.logger.regex=.*TestContainer.*

Usage:

# Only log messages containing "TestContainer"
verifyica.engine.logger.regex=.*TestContainer.*

# Only log messages from specific package
verifyica.engine.logger.regex=com\\.example\\.tests\\..*

Stack Trace Configuration

verifyica.engine.prune.stacktraces

Controls whether stack traces are pruned to remove framework internals.

  • Type: Boolean
  • Default: false
  • Example: verifyica.engine.prune.stacktraces=true

Usage:

# Prune stack traces for cleaner output
verifyica.engine.prune.stacktraces=true

Effect:

Without pruning:

at com.example.MyTest.testMethod(MyTest.java:42)
at org.verifyica.engine.internal.TestExecutor.execute(TestExecutor.java:123)
at org.verifyica.engine.internal.ArgumentProcessor.process(ArgumentProcessor.java:456)
at org.verifyica.engine.internal.ClassProcessor.process(ClassProcessor.java:789)
... 50 more framework lines

With pruning:

at com.example.MyTest.testMethod(MyTest.java:42)

Filter Configuration

verifyica.engine.filter.definitions.filename

Specifies the YAML file containing filter definitions.

  • Type: String (filename)
  • Default: verifyica.engine.filter.definitions.yaml
  • Example: verifyica.engine.filter.definitions.filename=my-filters.yaml

Usage:

# Use custom filter file
verifyica.engine.filter.definitions.filename=my-filters.yaml

See Filters for complete filter documentation.

Interceptor Configuration

These properties control which interceptors are automatically discovered and loaded.

verifyica.engine.autowired.engine.interceptors.exclude.regex

Exclude EngineInterceptors by regex pattern.

  • Type: Regular expression
  • Default: (none)
  • Example: verifyica.engine.autowired.engine.interceptors.exclude.regex=.*Debug.*

verifyica.engine.autowired.engine.interceptors.include.regex

Include only EngineInterceptors matching regex pattern.

  • Type: Regular expression
  • Default: (none - all included)
  • Example: verifyica.engine.autowired.engine.interceptors.include.regex=com\\.example\\..*

verifyica.engine.autowired.class.interceptors.exclude.regex

Exclude ClassInterceptors by regex pattern.

  • Type: Regular expression
  • Default: (none)
  • Example: verifyica.engine.autowired.class.interceptors.exclude.regex=.*Debug.*

verifyica.engine.autowired.class.interceptors.include.regex

Include only ClassInterceptors matching regex pattern.

  • Type: Regular expression
  • Default: (none - all included)
  • Example: verifyica.engine.autowired.class.interceptors.include.regex=com\\.example\\..*

Usage:

# Only load interceptors from specific package
verifyica.engine.autowired.class.interceptors.include.regex=com\\.example\\.interceptors\\..*

# Exclude debug interceptors in production
verifyica.engine.autowired.class.interceptors.exclude.regex=.*Debug.*

Maven Plugin Properties

These properties configure the Maven plugin behavior.

verifyica.maven.plugin.log.tests

Controls whether the Maven plugin logs test execution.

  • Type: Boolean
  • Default: false
  • Example: verifyica.maven.plugin.log.tests=true

Usage:

# Enable test logging in Maven plugin
verifyica.maven.plugin.log.tests=true

verifyica.maven.plugin.log.timing.units

Sets the time unit for Maven plugin timing logs.

  • Type: String
  • Values: nanoseconds, microseconds, milliseconds, seconds
  • Default: milliseconds
  • Example: verifyica.maven.plugin.log.timing.units=seconds

Usage:

# Log timing in seconds
verifyica.maven.plugin.log.timing.units=seconds

Complete Configuration Example

Here’s a comprehensive verifyica.properties file:

# Parallelism Configuration
verifyica.engine.class.parallelism=4
verifyica.engine.argument.parallelism=2

# Thread Configuration
verifyica.engine.thread.type=virtual

# Logging Configuration
verifyica.engine.logger.level=INFO
verifyica.engine.logger.regex=

# Stack Trace Configuration
verifyica.engine.prune.stacktraces=true

# Filter Configuration
verifyica.engine.filter.definitions.filename=verifyica.engine.filter.definitions.yaml

# Interceptor Configuration
verifyica.engine.autowired.class.interceptors.include.regex=com\\.example\\.interceptors\\..*
verifyica.engine.autowired.class.interceptors.exclude.regex=.*Debug.*

# Maven Plugin Configuration
verifyica.maven.plugin.log.tests=true
verifyica.maven.plugin.log.timing.units=milliseconds

Environment-Specific Configuration

Development

verifyica.engine.argument.parallelism=1  # Sequential for easier debugging
verifyica.engine.logger.level=DEBUG
verifyica.engine.prune.stacktraces=false  # Full stack traces

CI/CD

verifyica.engine.class.parallelism=4
verifyica.engine.argument.parallelism=4
verifyica.engine.thread.type=virtual
verifyica.engine.logger.level=INFO
verifyica.engine.prune.stacktraces=true

Production Integration Tests

verifyica.engine.argument.parallelism=1  # Sequential for stability
verifyica.engine.logger.level=WARN
verifyica.engine.prune.stacktraces=true

Next Steps

2 - Filters

Include or exclude tests using YAML-based filters

Verifyica provides a powerful YAML-based filtering system to control which tests execute based on class names, packages, tags, and patterns.

Filter Configuration File

Filters are defined in a YAML file, by default verifyica.engine.filter.definitions.yaml in the classpath.

Location

Place the filter file in:

src/test/resources/verifyica.engine.filter.definitions.yaml

Custom Filename

Configure a custom filename via properties:

verifyica.engine.filter.definitions.filename=my-filters.yaml

Filter Structure

The filter file has two main sections: include and exclude.

Basic Structure

include:
  - # Include filters

exclude:
  - # Exclude filters

Filter Priority

  1. Exclude filters are evaluated first
  2. Include filters are evaluated second
  3. If a test matches an exclude filter, it’s excluded regardless of include filters
  4. If no include filters are specified, all tests (not excluded) are included

Filter Types

Class Name Filters

Filter by exact class name:

include:
  - className: "com.example.tests.DatabaseTest"
  - className: "com.example.tests.ApiTest"

Package Filters

Filter by package name:

include:
  - packageName: "com.example.tests.integration"
  - packageName: "com.example.tests.unit"

Pattern Filters

Use regex patterns for flexible matching:

include:
  - pattern: ".*IntegrationTest"
  - pattern: "com\\.example\\.tests\\..*Test"

Tag Filters

Filter by @Tag annotations:

include:
  - tag: "fast"
  - tag: "unit"

exclude:
  - tag: "slow"
  - tag: "integration"

Tests are tagged using the @Tag annotation:

@Tag("fast")
@Tag("unit")
public class FastUnitTest {
    // Tests...
}

Complete Filter Examples

Example 1: Run Only Integration Tests

include:
  - tag: "integration"

Example 2: Exclude Slow Tests

exclude:
  - tag: "slow"

Example 3: Run Only Specific Package

include:
  - packageName: "com.example.tests.critical"

Example 4: Complex Filtering

include:
  # Include all integration tests
  - tag: "integration"
  # Include all tests in critical package
  - packageName: "com.example.tests.critical"
  # Include tests matching pattern
  - pattern: ".*SmokeTest"

exclude:
  # Exclude slow tests
  - tag: "slow"
  # Exclude experimental tests
  - tag: "experimental"
  # Exclude specific class
  - className: "com.example.tests.BrokenTest"

Example 5: Environment-Specific Filters

CI environment (fast tests only):

include:
  - tag: "ci"
  - tag: "fast"

exclude:
  - tag: "slow"
  - tag: "manual"

Local development (all except slow):

exclude:
  - tag: "slow"

Production validation (critical tests only):

include:
  - tag: "critical"
  - tag: "smoke"

Using Tags in Tests

Single Tag

import org.verifyica.api.Tag;

@Tag("integration")
public class IntegrationTest {
    // Tests...
}

Multiple Tags

@Tag("integration")
@Tag("database")
@Tag("slow")
public class DatabaseIntegrationTest {
    // Tests...
}

Method-Level Tags

Tags can be placed on individual test methods:

public class MixedTest {

    @Verifyica.Test
    @Tag("fast")
    public void fastTest(String argument) {
        // Fast test
    }

    @Verifyica.Test
    @Tag("slow")
    public void slowTest(String argument) {
        // Slow test
    }
}

Note: Method-level tags require class-level filtering to work correctly. If the class is excluded, method-level tags won’t be evaluated.

Filter Matching Logic

Multiple Filters of Same Type (OR logic)

Multiple filters of the same type use OR logic:

include:
  - tag: "unit"
  - tag: "integration"

This includes tests with tag “unit” OR “integration”.

Different Filter Types (AND logic)

Different filter types use AND logic:

include:
  - packageName: "com.example.tests"
  - tag: "integration"

This includes tests in package “com.example.tests” AND with tag “integration”.

Exclude Takes Precedence

include:
  - tag: "integration"

exclude:
  - className: "com.example.tests.BrokenIntegrationTest"

BrokenIntegrationTest is excluded even though it has the “integration” tag.

Common Filter Patterns

Run Only Unit Tests

include:
  - tag: "unit"

Run Everything Except Slow Tests

exclude:
  - tag: "slow"

Run Only Tests in Specific Package

include:
  - packageName: "com.example.tests.smoke"

Run Integration Tests Except Database Tests

include:
  - tag: "integration"

exclude:
  - tag: "database"

Run All Tests Ending with “SmokeTest”

include:
  - pattern: ".*SmokeTest"

Dynamic Filter Files

Maven Profiles

Use Maven profiles to switch filter files:

<profiles>
    <profile>
        <id>ci</id>
        <build>
            <resources>
                <resource>
                    <directory>src/test/resources/filters</directory>
                    <includes>
                        <include>ci-filters.yaml</include>
                    </includes>
                    <targetPath>.</targetPath>
                    <filtering>false</filtering>
                </resource>
            </resources>
        </build>
        <properties>
            <verifyica.engine.filter.definitions.filename>ci-filters.yaml</verifyica.engine.filter.definitions.filename>
        </properties>
    </profile>
</profiles>

Run with: mvn test -Pci

Environment-Based Configuration

Use system properties to switch filters:

# Use CI filters
mvn test -Dverifyica.engine.filter.definitions.filename=ci-filters.yaml

# Use integration test filters
mvn test -Dverifyica.engine.filter.definitions.filename=integration-filters.yaml

Troubleshooting Filters

No Tests Run

If no tests execute after adding filters:

  1. Check filter syntax - Ensure YAML is valid
  2. Verify tags - Ensure tests have matching tags
  3. Check exclusions - Exclude filters may be too broad
  4. Enable debug logging:
verifyica.engine.logger.level=DEBUG

Unexpected Tests Run

If unexpected tests execute:

  1. Check include filters - May be too broad
  2. Verify tag spelling - Tags are case-sensitive
  3. Check pattern syntax - Regex patterns must be escaped correctly

Filter Not Applied

If filters aren’t working:

  1. Verify file location - Must be in classpath (src/test/resources)
  2. Check filename - Default is verifyica.engine.filter.definitions.yaml
  3. Validate YAML syntax - Use a YAML validator

Best Practices

Use Descriptive Tag Names

// Good: Clear, descriptive tags
@Tag("database-integration")
@Tag("requires-docker")
@Tag("slow")

// Bad: Cryptic tags
@Tag("t1")
@Tag("x")

Organize Tags by Category

// Execution speed
@Tag("fast")  // < 1 second
@Tag("medium")  // 1-10 seconds
@Tag("slow")  // > 10 seconds

// Test type
@Tag("unit")
@Tag("integration")
@Tag("e2e")

// Dependencies
@Tag("requires-database")
@Tag("requires-docker")
@Tag("requires-network")

Document Filter Files

# CI Filter Configuration
# Runs fast, critical tests suitable for PR validation
include:
  - tag: "fast"
  - tag: "critical"

exclude:
  - tag: "slow"
  - tag: "flaky"  # Exclude flaky tests from CI

Keep Filter Files Simple

Start with simple filters and add complexity only as needed:

# Simple: Good starting point
include:
  - tag: "ci"

# Complex: Only if needed
include:
  - tag: "integration"
  - packageName: "com.example.critical"
  - pattern: ".*SmokeTest"
exclude:
  - tag: "slow"
  - tag: "flaky"
  - className: "com.example.BrokenTest"

Next Steps

3 - Parallelism

Configure parallel test execution at class, argument, and test levels

Verifyica provides three levels of parallelism control to optimize test execution time while maintaining test isolation.

Parallelism Levels

Verifyica supports parallelism at three levels:

  1. Class-level - Multiple test classes execute in parallel
  2. Argument-level - Multiple arguments within a class execute in parallel
  3. Test-level - Multiple test methods within an argument execute in parallel

Class-Level Parallelism

Control how many test classes execute concurrently.

Configuration

verifyica.engine.class.parallelism=4

Example

With class.parallelism=4:

TestClass1 (Thread 1)
TestClass2 (Thread 2)
TestClass3 (Thread 3)
TestClass4 (Thread 4)
TestClass5 (waits for a thread to become available)

Recommendations

  • Small test suites: 1-2
  • Medium test suites: 2-4
  • Large test suites: 4-8
  • CI/CD with many cores: Match available CPU cores

Argument-Level Parallelism

Control how many arguments within a test class execute concurrently.

Configuration

Default for all classes:

verifyica.engine.argument.parallelism=2

Per-class override:

@Verifyica.ArgumentSupplier(parallelism = 4)
public static Collection<String> arguments() {
    return generateArguments();
}

Example

With parallelism = 2 and 5 arguments:

For TestClass1:
  arg1 (Thread 1)
  arg2 (Thread 2)
  arg3 (waits for Thread 1 or 2)
  arg4 (waits)
  arg5 (waits)

When to Use

Good candidates for high parallelism:

  • Independent test arguments
  • I/O-bound tests (database, network, file operations)
  • Tests with significant wait times
  • Container-based tests

Keep parallelism low (1-2) when:

  • Tests share mutable state
  • Tests use limited resources (ports, database connections)
  • Tests are CPU-intensive
  • Debugging tests

Example: Independent Arguments

@Verifyica.ArgumentSupplier(parallelism = 4)
public static Collection<Argument<Config>> arguments() {
    // Each config is completely independent
    return Arrays.asList(
        Argument.of("h2", new Config("jdbc:h2:mem:test1")),
        Argument.of("postgres", new Config("jdbc:postgresql://localhost/test2")),
        Argument.of("mysql", new Config("jdbc:mysql://localhost/test3")),
        Argument.of("oracle", new Config("jdbc:oracle://localhost/test4"))
    );
}

Example: Resource-Constrained

@Verifyica.ArgumentSupplier(parallelism = 1)
public static Collection<Argument<Integer>> arguments() {
    // All use same port - must be sequential
    return Arrays.asList(
        Argument.of("port-8080", 8080),
        Argument.of("port-8080-again", 8080)  // Would conflict if parallel
    );
}

Test-Level Parallelism

Control how many test methods within an argument execute concurrently.

Warning: Test-level parallelism requires careful state management to avoid race conditions.

Configuration

# Currently not configurable via annotation
# Controlled globally via properties
# (Check latest documentation for current support)

Thread Safety Requirements

If test methods run in parallel within an argument:

  • Instance variables must be thread-safe
  • Use thread-safe collections
  • Synchronize access to shared state

Example: Parallel-Safe Tests

public class ParallelSafeTest {

    private final AtomicInteger counter = new AtomicInteger(0);
    private final Connection connection; // Shared, must be thread-safe

    @Verifyica.BeforeAll
    public void beforeAll(Config config) {
        connection = database.connect(config);
    }

    @Verifyica.Test
    public void test1(Config config) {
        int value = counter.incrementAndGet(); // Thread-safe
        connection.execute("SELECT " + value);  // Connection must be thread-safe!
    }

    @Verifyica.Test
    public void test2(Config config) {
        int value = counter.incrementAndGet(); // Thread-safe
        connection.execute("SELECT " + value);
    }
}

Thread Types

Configure the type of threads used for parallel execution.

Configuration

verifyica.engine.thread.type=virtual

Thread Type Options

TypeDescriptionBest ForJava Version
virtualJava virtual threadsHigh concurrency, I/O-boundJava 21+
platformTraditional OS threadsCPU-bound, Java 8+Java 8+
platform-ephemeralThreads discarded after useThreadLocal state isolationJava 8+

Virtual Threads (Java 21+)

Virtual threads enable massive concurrency with minimal overhead:

verifyica.engine.thread.type=virtual
verifyica.engine.argument.parallelism=100

Benefits:

  • Extremely lightweight (1000s of virtual threads possible)
  • Ideal for I/O-bound operations
  • Minimal memory footprint

Example:

// With virtual threads, high parallelism is practical
@Verifyica.ArgumentSupplier(parallelism = 50)
public static Collection<String> arguments() {
    // 50 concurrent arguments with minimal overhead
    return IntStream.range(0, 1000)
        .mapToObj(i -> "arg-" + i)
        .collect(Collectors.toList());
}

Platform Threads

Traditional OS threads:

verifyica.engine.thread.type=platform
verifyica.engine.argument.parallelism=4

Benefits:

  • Compatible with all Java versions
  • Predictable behavior
  • Better for CPU-bound operations

Platform Ephemeral Threads

Platform threads that are discarded after use:

verifyica.engine.thread.type=platform-ephemeral

Benefits:

  • Isolates ThreadLocal state between arguments
  • Prevents ThreadLocal memory leaks
  • Useful for tests that use ThreadLocal

Parallelism Best Practices

Start Sequential, Then Parallelize

// Step 1: Get tests working sequentially
@Verifyica.ArgumentSupplier(parallelism = 1)
public static Collection<String> arguments() {
    return generateArguments();
}

// Step 2: Once stable, increase parallelism
@Verifyica.ArgumentSupplier(parallelism = 4)
public static Collection<String> arguments() {
    return generateArguments();
}

Match Parallelism to Resources

// Good: Parallelism matches available database connections
private static final int MAX_CONNECTIONS = 4;

@Verifyica.ArgumentSupplier(parallelism = 4)
public static Collection<Config> arguments() {
    // 4 arguments can run in parallel with 4 connections
    return generateConfigs();
}

Use Virtual Threads for I/O-Bound Tests

# I/O-bound tests (network, database, files)
verifyica.engine.thread.type=virtual
verifyica.engine.argument.parallelism=20

# CPU-bound tests (computation, algorithms)
verifyica.engine.thread.type=platform
verifyica.engine.argument.parallelism=4

Isolate State for Parallel Execution

// Good: Isolated state per argument using context classes
public class IsolatedTest {
    // Define a context class to encapsulate per-argument state
    public static class TestContext {
        private final Connection connection;

        public TestContext(Connection connection) {
            this.connection = connection;
        }

        public Connection getConnection() {
            return connection;
        }
    }

    @Verifyica.ArgumentSupplier(parallelism = 4)
    public static Collection<Argument<Config>> arguments() {
        return getArguments();
    }

    @Verifyica.BeforeAll
    public void beforeAll(ArgumentContext argumentContext) {
        Config config = argumentContext.getArgument().getPayloadAs(Config.class);
        Connection conn = database.connect(config);

        // Store context in ArgumentContext map (thread-safe)
        TestContext context = new TestContext(conn);
        argumentContext.getMap().put("testContext", context);
    }

    @Verifyica.Test
    public void test(ArgumentContext argumentContext) {
        TestContext context = (TestContext) argumentContext.getMap().get("testContext");
        context.getConnection().execute("SELECT 1");
    }

    @Verifyica.AfterAll
    public void afterAll(ArgumentContext argumentContext) {
        TestContext context = (TestContext) argumentContext.getMap().get("testContext");
        if (context != null && context.getConnection() != null) {
            context.getConnection().close();
        }
    }
}

// Bad: Shared mutable instance variable with parallelism
public class SharedStateTest {

    private Connection connection; // UNSAFE: race condition with parallel arguments!

    @Verifyica.ArgumentSupplier(parallelism = 4)
    public static Collection<Config> arguments() {
        return getConfigs();
    }

    @Verifyica.BeforeAll
    public void beforeAll(Config config) {
        connection = database.connect(config); // Race condition!
    }

    @Verifyica.Test
    public void test(Config config) {
        connection.execute("SELECT 1"); // May use wrong connection!
    }
}

Monitor Performance

Use interceptors to measure the impact of parallelism:

public class PerformanceInterceptor implements ClassInterceptor {
    private long startTime;

    @Override
    public void prePrepare(ClassContext classContext, Method method) {
        startTime = System.currentTimeMillis();
    }

    @Override
    public void postConclude(ClassContext classContext, Method method, Throwable throwable) {
        long duration = System.currentTimeMillis() - startTime;
        String className = classContext.getTestClass().getSimpleName();
        System.out.printf("%s completed in %d ms%n", className, duration);
    }
}

Parallelism Troubleshooting

Tests Fail Only When Parallel

Symptoms:

  • Tests pass with parallelism=1
  • Tests fail with parallelism>1

Causes:

  1. Shared mutable state
  2. Race conditions
  3. Resource contention
  4. Improper synchronization

Solution:

// Use thread-safe collections
private final ConcurrentHashMap<String, Result> results = new ConcurrentHashMap<>();

// Use atomic operations
private final AtomicInteger counter = new AtomicInteger(0);

// Synchronize access to shared resources
private synchronized void updateSharedState() {
    // Critical section
}

Tests Are Slower with Parallelism

Causes:

  1. Too much parallelism (thread overhead)
  2. Resource contention (database, CPU)
  3. Shared locks or bottlenecks

Solution:

# Reduce parallelism
verifyica.engine.argument.parallelism=2

# Try different thread type
verifyica.engine.thread.type=platform

Deadlocks or Hangs

Causes:

  1. Circular dependencies
  2. Resource exhaustion
  3. Improper locking

Solution:

# Disable parallelism for debugging
verifyica.engine.argument.parallelism=1

# Enable debug logging
verifyica.engine.logger.level=DEBUG

Performance Examples

Example 1: TestContainers with Parallelism

@Verifyica.ArgumentSupplier(parallelism = 3)
public static Collection<Argument<Container>> arguments() {
    // Start 3 containers in parallel
    return Arrays.asList(
        Argument.of("nginx", new NginxContainer()),
        Argument.of("postgres", new PostgreSQLContainer()),
        Argument.of("redis", new RedisContainer())
    );
}

With parallelism:

  • Sequential: 90 seconds (30s × 3)
  • Parallel (3): 30 seconds (3 containers start simultaneously)

Example 2: API Testing

@Verifyica.ArgumentSupplier(parallelism = 10)
public static Collection<String> arguments() {
    // Test 100 API endpoints
    return generateEndpoints(); // Returns 100 endpoints
}

With parallelism=10 and virtual threads:

  • Sequential: 1000 seconds (10s × 100)
  • Parallel (10): 100 seconds (10 at a time)

Configuration Examples

Development Environment

# Low parallelism for easier debugging
verifyica.engine.class.parallelism=1
verifyica.engine.argument.parallelism=1
verifyica.engine.thread.type=platform
verifyica.engine.logger.level=DEBUG

CI/CD Environment

# High parallelism for speed
verifyica.engine.class.parallelism=8
verifyica.engine.argument.parallelism=4
verifyica.engine.thread.type=virtual
verifyica.engine.logger.level=INFO

Integration Testing

# Moderate parallelism, balanced for resources
verifyica.engine.class.parallelism=2
verifyica.engine.argument.parallelism=2
verifyica.engine.thread.type=platform

Next Steps