PageSourceSearch

https://serenity-bdd.github.io/assets/js/d2fe653c.9236a288.js

js serenity-bdd.github.io collected 2026-10-03 09:56:38 UTC 33,027 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkserenity_users_guide=globalThis.webpackChunkserenity_users_guide||[]).push([[4295],{1723(e,n,i){i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"junit5/parallel-execution","title":"Running JUnit 5 Tests in Parallel","description":"Running JUnit 5 tests in parallel can significantly reduce test execution time. This guide explains how to configure and optimize parallel execution for Serenity BDD tests using JUnit 5.","source":"@site/docs/junit5/parallel-execution.md","sourceDirName":"junit5","slug":"/junit5/parallel-execution","permalink":"/docs/junit5/parallel-execution","draft":false,"unlisted":false,"editUrl":"https://github.com/serenity-bdd/serenity-bdd.github.io/blob/master/docs/junit5/parallel-execution.md","tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"id":"parallel-execution","title":"Running JUnit 5 Tests in Parallel","sidebar_position":2},"sidebar":"tutorialSidebar","previous":{"title":"JUnit 5 with Serenity BDD","permalink":"/docs/junit5/junit5-tests"},"next":{"title":"Cucumber with JUnit 5","permalink":"/docs/cucumber/cucumber-junit5"}}');var t=i(4848),a=i(8453);const r={id:"parallel-execution",title:"Running JUnit 5 Tests in Parallel",sidebar_position:2},l="Running JUnit 5 Serenity Tests in Parallel",c={},o=[{value:"Overview",id:"overview",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Basic Configuration",id:"basic-configuration",level:2},{value:"Step 1: Enable Parallel Execution",id:"step-1-enable-parallel-execution",level:3},{value:"Step 2: Configure Execution Mode",id:"step-2-configure-execution-mode",level:3},{value:"Step 3: Configure Execution Strategy",id:"step-3-configure-execution-strategy",level:3},{value:"Execution Modes",id:"execution-modes",level:2},{value:"Concurrent Mode",id:"concurrent-mode",level:3},{value:"Same Thread Mode",id:"same-thread-mode",level:3},{value:"Mixed Mode",id:"mixed-mode",level:3},{value:"Execution Strategies",id:"execution-strategies",level:2},{value:"Dynamic Strategy (Recommended)",id:"dynamic-strategy-recommended",level:3},{value:"Fixed Strategy",id:"fixed-strategy",level:3},{value:"Custom Strategy",id:"custom-strategy",level:3},{value:"Controlling Parallelism at Class/Method Level",id:"controlling-parallelism-at-classmethod-level",level:2},{value:"Per-Class Configuration",id:"per-class-configuration",level:3},{value:"Force Sequential Execution",id:"force-sequential-execution",level:3},{value:"Method-Level Control",id:"method-level-control",level:3},{value:"Resource Locks",id:"resource-locks",level:2},{value:"Common Resource Locks",id:"common-resource-locks",level:3},{value:"Thread Safety with Serenity",id:"thread-safety-with-serenity",level:2},{value:"WebDriver Management",id:"webdriver-management",level:3},{value:"Step Libraries",id:"step-libraries",level:3},{value:"Avoid Shared Mutable State",id:"avoid-shared-mutable-state",level:3},{value:"Complete Configuration Example",id:"complete-configuration-example",level:2},{value:"Comprehensive junit-platform.properties",id:"comprehensive-junit-platformproperties",level:3},{value:"Maven Configuration",id:"maven-configuration",level:2},{value:"Failsafe Plugin",id:"failsafe-plugin",level:3},{value:"Running from Command Line",id:"running-from-command-line",level:3},{value:"Gradle Configuration",id:"gradle-configuration",level:2},{value:"Performance Optimization",id:"performance-optimization",level:2},{value:"1. Choose the Right Strategy",id:"1-choose-the-right-strategy",level:3},{value:"2. Monitor Resource Usage",id:"2-monitor-resource-usage",level:3},{value:"3. Optimize Test Design",id:"3-optimize-test-design",level:3},{value:"4. Balance Thread Count",id:"4-balance-thread-count",level:3},{value:"Debugging Parallel Tests",id:"debugging-parallel-tests",level:2},{value:"Temporarily Disable Parallelism",id:"temporarily-disable-parallelism",level:3},{value:"Run Single Test Class",id:"run-single-test-class",level:3},{value:"Enable Verbose Logging",id:"enable-verbose-logging",level:3},{value:"Common Issues and Solutions",id:"common-issues-and-solutions",level:2},{value:"Issue 1: Flaky Tests",id:"issue-1-flaky-tests",level:3},{value:"Issue 2: Resource Exhaustion",id:"issue-2-resource-exhaustion",level:3},{value:"Issue 3: WebDriver Issues",id:"issue-3-webdriver-issues",level:3},{value:"Issue 4: Database Locks",id:"issue-4-database-locks",level:3},{value:"Best Practices",id:"best-practices",level:2},{value:"1. Start Small",id:"1-start-small",level:3},{value:"2. Isolate Test Data",id:"2-isolate-test-data",level:3},{value:"3. Use Tags for Selective Parallelism",id:"3-use-tags-for-selective-parallelism",level:3},{value:"4. Clean Up Resources",id:"4-clean-up-resources",level:3},{value:"5. Document Thread Safety",id:"5-document-thread-safety",level:3},{value:"Measuring Performance",id:"measuring-performance",level:2},{value:"Before Parallel Execution",id:"before-parallel-execution",level:3},{value:"After Parallel Execution (8 threads)",id:"after-parallel-execution-8-threads",level:3},{value:"Next Steps",id:"next-steps",level:2},{value:"Additional Resources",id:"additional-resources",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"running-junit-5-serenity-tests-in-parallel",children:"Running JUnit 5 Serenity Tests in Parallel"})}),"\n",(0,t.jsx)(n.p,{children:"Running JUnit 5 tests in parallel can significantly reduce test execution time. This guide explains how to configure and optimize parallel execution for Serenity BDD tests using JUnit 5."}),"\n",(0,t.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,t.jsx)(n.p,{children:"JUnit 5 (Jupiter) has built-in supp
1ort for parallel test execution. When combined with Serenity BDD, you can run test methods and test classes concurrently, taking advantage of multi-core processors."}),"\n",(0,t.jsx)(n.admonition,{title:"Parallel Execution Benefits",type:"tip",children:(0,t.jsx)(n.p,{children:"On a machine with 8 cores, parallel execution can reduce test time from 30 minutes to 5-8 minutes or less."})}),"\n",(0,t.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"JUnit 5 (Jupiter)"}),"\n",(0,t.jsx)(n.li,{children:"Serenity BDD 3.6.0 or higher"}),"\n",(0,t.jsx)(n.li,{children:"Thread-safe test code"}),"\n",(0,t.jsx)(n.li,{children:"Sufficient system resources (CPU, RAM)"}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"basic-configuration",children:"Basic Configuration"}),"\n",(0,t.jsx)(n.h3,{id:"step-1-enable-parallel-execution",children:"Step 1: Enable Parallel Execution"}),"\n",(0,t.jsxs)(n.p,{children:["Create or update ",(0,t.jsx)(n.code,{children:"junit-platform.properties"})," in ",(0,t.jsx)(n.code,{children:"src/test/resources"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# Enable parallel execution\njunit.jupiter.execution.parallel.enabled=true\n"})}),"\n",(0,t.jsx)(n.h3,{id:"step-2-configure-execution-mode",children:"Step 2: Configure Execution Mode"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# Run test classes in parallel\njunit.jupiter.execution.parallel.mode.default=concurrent\n\n# Run test classes in parallel\njunit.jupiter.execution.parallel.mode.classes.default=concurrent\n"})}),"\n",(0,t.jsx)(n.h3,{id:"step-3-configure-execution-strategy",children:"Step 3: Configure Execution Strategy"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# Use dynamic strategy (recommended)\njunit.jupiter.execution.parallel.config.strategy=dynamic\njunit.jupiter.execution.parallel.config.dynamic.factor=1.0\n"})}),"\n",(0,t.jsx)(n.h2,{id:"execution-modes",children:"Execution Modes"}),"\n",(0,t.jsx)(n.h3,{id:"concurrent-mode",children:"Concurrent Mode"}),"\n",(0,t.jsx)(n.p,{children:"Tests run in parallel:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.mode.default=concurrent\njunit.jupiter.execution.parallel.mode.classes.default=concurrent\n"})}),"\n",(0,t.jsx)(n.h3,{id:"same-thread-mode",children:"Same Thread Mode"}),"\n",(0,t.jsx)(n.p,{children:"Tests run sequentially:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.mode.default=same_thread\njunit.jupiter.execution.parallel.mode.classes.default=same_thread\n"})}),"\n",(0,t.jsx)(n.h3,{id:"mixed-mode",children:"Mixed Mode"}),"\n",(0,t.jsx)(n.p,{children:"Run classes in parallel but methods within a class sequentially:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# Classes in parallel\njunit.jupiter.execution.parallel.mode.classes.default=concurrent\n\n# Methods in same class run sequentially\njunit.jupiter.execution.parallel.mode.default=same_thread\n"})}),"\n",(0,t.jsx)(n.h2,{id:"execution-strategies",children:"Execution Strategies"}),"\n",(0,t.jsx)(n.h3,{id:"dynamic-strategy-recommended",children:"Dynamic Strategy (Recommended)"}),"\n",(0,t.jsx)(n.p,{children:"Automatically determines thread count based on available processors:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.config.strategy=dynamic\njunit.jupiter.execution.parallel.config.dynamic.factor=1.0\n"})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Factor calculation:"})," ",(0,t.jsx)(n.code,{children:"threads = processors \xd7 factor"})]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Examples"})," (on an 8-core machine):"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Factor ",(0,t.jsx)(n.code,{children:"1.0"})," = 8 threads (recommended)"]}),"\n",(0,t.jsxs)(n.li,{children:["Factor ",(0,t.jsx)(n.code,{children:"0.5"})," = 4 threads"]}),"\n",(0,t.jsxs)(n.li,{children:["Factor ",(0,t.jsx)(n.code,{children:"2.0"})," = 16 threads"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"fixed-strategy",children:"Fixed Strategy"}),"\n",(0,t.jsx)(n.p,{children:"Uses a specified number of threads:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.config.strategy=fixed\njunit.jupiter.execution.parallel.config.fixed.parallelism=4\n"})}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Use when:"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"You need consistent thread counts"}),"\n",(0,t.jsx)(n.li,{children:"Running on shared CI/CD infrastru
1cture"}),"\n",(0,t.jsx)(n.li,{children:"Debugging parallel execution issues"}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"custom-strategy",children:"Custom Strategy"}),"\n",(0,t.jsx)(n.p,{children:"Implement your own strategy:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.config.strategy=custom\njunit.jupiter.execution.parallel.config.custom.class=com.example.MyParallelStrategy\n"})}),"\n",(0,t.jsx)(n.h2,{id:"controlling-parallelism-at-classmethod-level",children:"Controlling Parallelism at Class/Method Level"}),"\n",(0,t.jsx)(n.h3,{id:"per-class-configuration",children:"Per-Class Configuration"}),"\n",(0,t.jsxs)(n.p,{children:["Use ",(0,t.jsx)(n.code,{children:"@Execution"})," annotation to control parallelism:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"import org.junit.jupiter.api.parallel.Execution;\nimport org.junit.jupiter.api.parallel.ExecutionMode;\n\n@ExtendWith(SerenityJUnit5Extension.class)\n@Execution(ExecutionMode.CONCURRENT)  // Run this class's methods in parallel\nclass FastTests {\n\n    @Test\n    void test1() { }\n\n    @Test\n    void test2() { }\n\n    @Test\n    void test3() { }\n}\n"})}),"\n",(0,t.jsx)(n.h3,{id:"force-sequential-execution",children:"Force Sequential Execution"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"@ExtendWith(SerenityJUnit5Extension.class)\n@Execution(ExecutionMode.SAME_THREAD)  // Run sequentially\nclass DatabaseMigrationTests {\n\n    @Test\n    void migration1() { }\n\n    @Test\n    void migration2() { }  // Must run after migration1\n}\n"})}),"\n",(0,t.jsx)(n.h3,{id:"method-level-control",children:"Method-Level Control"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"@ExtendWith(SerenityJUnit5Extension.class)\nclass MixedTests {\n\n    @Test\n    @Execution(ExecutionMode.CONCURRENT)\n    void canRunInParallel() { }\n\n    @Test\n    @Execution(ExecutionMode.SAME_THREAD)\n    void mustRunSequentially() { }\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"resource-locks",children:"Resource Locks"}),"\n",(0,t.jsx)(n.p,{children:"Prevent concurrent access to shared resources:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'import org.junit.jupiter.api.parallel.ResourceLock;\n\n@ExtendWith(SerenityJUnit5Extension.class)\nclass SharedResourceTests {\n\n    @Test\n    @ResourceLock("database")\n    void accessDatabase1() {\n        // Exclusive access to database\n    }\n\n    @Test\n    @ResourceLock("database")\n    void accessDatabase2() {\n        // Will wait for accessDatabase1 to complete\n    }\n\n    @Test\n    @ResourceLock(value = "database", mode = READ)\n    void readFromDatabase() {\n        // Read-only access - can run concurrently with other reads\n    }\n}\n'})}),"\n",(0,t.jsx)(n.h3,{id:"common-resource-locks",children:"Common Resource Locks"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'import static org.junit.jupiter.api.parallel.Resources.*;\n\n@Test\n@ResourceLock(SYSTEM_PROPERTIES)\nvoid modifiesSystemProperties() { }\n\n@Test\n@ResourceLock(SYSTEM_OUT)\nvoid writesToSystemOut() { }\n\n@Test\n@ResourceLock("my-custom-resource")\nvoid accessesCustomResource() { }\n'})}),"\n",(0,t.jsx)(n.h2,{id:"thread-safety-with-serenity",children:"Thread Safety with Serenity"}),"\n",(0,t.jsx)(n.h3,{id:"webdriver-management",children:"WebDriver Management"}),"\n",(0,t.jsxs)(n.p,{children:["Serenity's ",(0,t.jsx)(n.code,{children:"@Managed"})," WebDriver is automatically thread-safe:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'@ExtendWith(SerenityJUnit5Extension.class)\n@Execution(ExecutionMode.CONCURRENT)\nclass WebTests {\n\n    @Managed(driver = "chrome", options = "headless")\n    WebDriver driver;  // Each thread gets its own instance\n\n    @Test\n    void test1() {\n        driver.get("https://example.com");\n        // Thread-safe\n    }\n\n    @Test\n    void test2() {\n        driver.get("https://example.com/other");\n        // Independent WebDriver instance\n    }\n}\n'})}),"\n",(0,t.jsx)(n.h3,{id:"step-libraries",children:"Step Libraries"}),"\n",(0,t.jsx)(n.p,{children:"Step libraries are thread-safe when properly used:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'@ExtendWith(SerenityJUnit5Extension.class)\n@Execution(ExecutionMode.CONCURRENT)\nclass CheckoutTests {\n\n    @Steps\n    CartSteps cart;  // Thread-safe - instance per thread\n\n    @Test\n    void addToCart() {\n        cart.addProduct("Product1");\n    }\n\n    @Test\n    void removeFromCart() {\n        cart.addProduct("Product2");\n        cart.removeProduct("Product2");\n    }\n}\n'})}),"\n",(0,t.jsx)(n.h3,{id:"avoid-shared-mutable-state",children:"Avoid Shared Mutable State"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'// \u274c BAD - 
1Not thread-safe\n@ExtendWith(SerenityJUnit5Extension.class)\n@Execution(ExecutionMode.CONCURRENT)\nclass BadTests {\n\n    private String sharedData;  // Shared mutable state!\n\n    @Test\n    void test1() {\n        sharedData = "test1";  // Race condition!\n    }\n\n    @Test\n    void test2() {\n        sharedData = "test2";  // Race condition!\n    }\n}\n\n// \u2705 GOOD - Thread-safe\n@ExtendWith(SerenityJUnit5Extension.class)\n@Execution(ExecutionMode.CONCURRENT)\nclass GoodTests {\n\n    @Test\n    void test1() {\n        String localData = "test1";  // Local variable - thread-safe\n        // Use localData\n    }\n\n    @Test\n    void test2() {\n        String localData = "test2";  // Independent\n        // Use localData\n    }\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"complete-configuration-example",children:"Complete Configuration Example"}),"\n",(0,t.jsx)(n.h3,{id:"comprehensive-junit-platformproperties",children:"Comprehensive junit-platform.properties"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# ==========================================\n# Parallel Execution\n# ==========================================\njunit.jupiter.execution.parallel.enabled=true\njunit.jupiter.execution.parallel.mode.default=concurrent\njunit.jupiter.execution.parallel.mode.classes.default=concurrent\n\n# ==========================================\n# Execution Strategy\n# ==========================================\njunit.jupiter.execution.parallel.config.strategy=dynamic\njunit.jupiter.execution.parallel.config.dynamic.factor=1.0\n\n# Alternative: Fixed strategy\n# junit.jupiter.execution.parallel.config.strategy=fixed\n# junit.jupiter.execution.parallel.config.fixed.parallelism=4\n# junit.jupiter.execution.parallel.config.fixed.max-pool-size=8\n\n# ==========================================\n# Test Instance Lifecycle\n# ==========================================\njunit.jupiter.testinstance.lifecycle.default=per_method\n\n# ==========================================\n# Test Discovery\n# ==========================================\njunit.jupiter.testclass.order.default=org.junit.jupiter.api.ClassOrderer$Random\n\n# ==========================================\n# Display Names\n# ==========================================\njunit.jupiter.displayname.generator.default=org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores\n"})}),"\n",(0,t.jsx)(n.h2,{id:"maven-configuration",children:"Maven Configuration"}),"\n",(0,t.jsx)(n.h3,{id:"failsafe-plugin",children:"Failsafe Plugin"}),"\n",(0,t.jsx)(n.p,{children:"Configure Maven Failsafe plugin for parallel execution:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-xml",children:"<plugin>\n    <groupId>org.apache.maven.plugins</groupId>\n    <artifactId>maven-failsafe-plugin</artifactId>\n    <version>3.0.0</version>\n    <configuration>\n        \x3c!-- Enable JUnit 5 --\x3e\n        <includes>\n            <include>**/*Test.java</include>\n            <include>**/*Tests.java</include>\n        </includes>\n\n        \x3c!-- System properties --\x3e\n        <systemPropertyVariables>\n            <webdriver.driver>${webdriver.driver}</webdriver.driver>\n            <environment>${environment}</environment>\n        </systemPropertyVariables>\n\n        \x3c!-- Increase memory for parallel execution --\x3e\n        <argLine>-Xmx2g</argLine>\n    </configuration>\n    <executions>\n        <execution>\n            <goals>\n                <goal>integration-test</goal>\n                <goal>verify</goal>\n            </goals>\n        </execution>\n    </executions>\n</plugin>\n"})}),"\n",(0,t.jsx)(n.h3,{id:"running-from-command-line",children:"Running from Command Line"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"# Run all tests in parallel\nmvn clean verify\n\n# Override parallelism\nmvn clean verify -Djunit.jupiter.execution.parallel.config.fixed.parallelism=8\n\n# Disable parallel execution\nmvn clean verify -Djunit.jupiter.execution.parallel.enabled=false\n"})}),"\n",(0,t.jsx)(n.h2,{id:"gradle-configuration",children:"Gradle Configuration"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-groovy",children:"test {\n    useJUnitPlatform()\n\n    // Enable parallel execution\n    maxParallelForks = Runtime.runtime.availableProcessors()\n\n    // Increase memory\n    minHeapSize = \"512m\"\n    maxHeapSize = \"2g\"\n\n    // System properties\n    systemProperty 'junit.jupiter.execution.parallel.enabled', 'true'\n    systemProperty 'junit.jupiter.execution.parallel.config.strategy', 'dynamic'\n    systemProperty 'junit.jupiter.execution.parallel.config.dynamic.factor', '1.0'\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"performance-optimization",children:"Performance Optimization"}),"\n",(0,t.jsx)(n.h3,{id:"1-choose-the-right-strategy",children:"1. Choose the Right Strategy"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Small test suites"})," (<30 tests):"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.config.strategy=fixed\njunit.jupiter.execution.parallel.config.fixed.parallelism=2\n"})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Medium test suites"})," (30-100 tests):"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.config.strategy=dynamic\njunit.jupiter.execution.parallel.config.dynamic.factor=1.0\n"})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Large test suites"})," (>100 tests):"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.config.strategy=dynamic\njunit.jupiter.execution.parallel.config.dynamic.factor=0.75\n"})}),"\n",(0,t.jsx)(n.h3,{id:"2-monitor-resource-usage",children:"2. Monitor Resource Usage"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"# Monitor while tests run\ntop\nhtop\njconsole\n"})}),"\n",(0,t.jsx)(n.p,{children:"Watch for:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"CPU"}),": Should be near 100% utilization"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Memory"}),": Each browser instance uses ~200-500MB RAM"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"Threads"}),": Should match your parallelism setting"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"3-optimize-test-design",children:"3. Optimize Test Design"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"// \u2705 GOOD - Fast, focused tests\n@Test\nvoid shouldCalculateTotal() {\n    // No external dependencies, runs quickly\n    assertThat(calculator.add(2, 3)).isEqualTo(5);\n}\n\n// \u26a0\ufe0f SLOW - Consider optimization\n@Test\nvoid shouldProcessLargeDataset() {\n    // Process 10000 records - consider using smaller dataset\n}\n"})}),"\n",(0,t.jsx)(n.h3,{id:"4-balance-thread-count",children:"4. Balance Thread Count"}),"\n",(0,t.jsx)(n.p,{children:"Too few threads:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# Underutilizing CPU\njunit.jupiter.execution.parallel.config.dynamic.factor=0.25\n"})}),"\n",(0,t.jsx)(n.p,{children:"Too many threads:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# May cause resource exh
1austion\njunit.jupiter.execution.parallel.config.dynamic.factor=4.0\n"})}),"\n",(0,t.jsx)(n.p,{children:"Optimal:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# Matches CPU cores\njunit.jupiter.execution.parallel.config.dynamic.factor=1.0\n"})}),"\n",(0,t.jsx)(n.h2,{id:"debugging-parallel-tests",children:"Debugging Parallel Tests"}),"\n",(0,t.jsx)(n.h3,{id:"temporarily-disable-parallelism",children:"Temporarily Disable Parallelism"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.enabled=false\n"})}),"\n",(0,t.jsx)(n.p,{children:"Or via command line:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"mvn verify -Djunit.jupiter.execution.parallel.enabled=false\n"})}),"\n",(0,t.jsx)(n.h3,{id:"run-single-test-class",children:"Run Single Test Class"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-bash",children:"mvn test -Dtest=MyTestClass\n"})}),"\n",(0,t.jsx)(n.h3,{id:"enable-verbose-logging",children:"Enable Verbose Logging"}),"\n",(0,t.jsxs)(n.p,{children:["Add to ",(0,t.jsx)(n.code,{children:"junit-platform.properties"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# Show which thread runs which test\njunit.platform.output.capture.stdout=true\njunit.platform.output.capture.stderr=true\n"})}),"\n",(0,t.jsx)(n.p,{children:"In your test:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'@BeforeEach\nvoid logThread() {\n    System.out.println("Running on: " + Thread.currentThread().getName());\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"common-issues-and-solutions",children:"Common Issues and Solutions"}),"\n",(0,t.jsx)(n.h3,{id:"issue-1-flaky-tests",children:"Issue 1: Flaky Tests"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Symptoms:"})," Tests pass individually but fail in parallel"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Solutions:"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Check for shared mutable state"}),"\n",(0,t.jsx)(n.li,{children:"Verify test data isolation"}),"\n",(0,t.jsx)(n.li,{children:"Review resource locking"}),"\n",(0,t.jsx)(n.li,{children:"Add proper synchronization"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"// Problem: Shared state\nprivate static int counter = 0;  // \u274c Not thread-safe\n\n@Test\nvoid incrementCounter() {\n    counter++;  // Race condition\n}\n\n// Solution: Use atomic types or local variables\nprivate static AtomicInteger counter = new AtomicInteger(0);  // \u2705 Thread-safe\n\n@Test\nvoid incrementCounter() {\n    counter.incrementAndGet();\n}\n"})}),"\n",(0,t.jsx)(n.h3,{id:"issue-2-resource-exhaustion",children:"Issue 2: Resource Exhaustion"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Symptoms:"})," Tests slow down or fail after some time"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Solutions:"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Reduce thread count"}),"\n",(0,t.jsx)(n.li,{children:"Increase JVM heap size"}),"\n",(0,t.jsx)(n.li,{children:"Check for resource leaks"}),"\n",(0,t.jsx)(n.li,{children:"Monitor system resources"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-xml",children:"\x3c!-- Increase heap size --\x3e\n<argLine>-Xmx4g</argLine>\n"})}),"\n",(0,t.jsx)(n.h3,{id:"issue-3-webdriver-issues",children:"Issue 3: WebDriver Issues"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Symptoms:"})," Browser instances multiply or don't close"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Solutions:"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Use ",(0,t.jsx)(n.code,{children:"@Managed"})," WebDriver (Serenity handles lifecycle)"]}),"\n",(0,t.jsxs)(n.li,{children:["Ensure proper cleanup in ",(0,t.jsx)(n.code,{children:"@AfterEach"})]}),"\n",(0,t.jsx)(n.li,{children:"Limit concurrent browser instances"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"// \u2705 Serenity manages lifecycle\n@Managed\nWebDriver driver;\n\n// \u274c Don't manage manually in parallel tests\nWebDriver driver = new ChromeDriver();  // Memory leak risk\n"})}),"\n",(0,t.jsx)(n.h3,{id:"issue-4-database-locks",children:"Issue 4: Database Locks"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.strong,{children:"Symptoms:"})," Tests timeout waiting for database"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Solutions:"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Use resource locks"}),"\n",(0,t.jsx)(n.li,{children:"Isolate test data"}),"\n",(0,t.jsx)(n.li,{children:"Use in-memory database for tests"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'@Test\n@ResourceLock("database")\nvoid modifiesDatabase() {\n    // Exclusive database access\n}\n'})}),"\n",(0,t.jsx)(n.h2,{id:"best-practices",children:"Best Practices"}),"\n",(0,t.jsx)(n.h3,{id:"1-start-small",children:"1. Start Small"}),"\n",(0,t.jsx)(n.p,{children:"Begin with 2-4 threads and gradually increase:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"junit.jupiter.execution.parallel.config.strategy=fixed\njunit.jupiter.execution.parallel.config.fixed.parallelism=2\n"})}),"\n",(0,t.jsx)(n.h3,{id:"2-isolate-test-data",children:"2. Isolate Test Data"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'@ExtendWith(SerenityJUnit5Extension.class)\nclass UserTests {\n\n    @Test\n    void createUser() {\n        String uniqueId = UUID.randomUUID().toString();\n        User user = createTestUser("user_" + uniqueId);\n        // Test with unique user\n    }\n}\n'})}),"\n",(0,t.jsx)(n.h3,{id:"3-use-tags-for-selective-parallelism",children:"3. Use Tags for Selective Parallelism"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:'@Test\n@Tag("parallel")\nvoid canRunInParallel() { }\n\n@Test\n@Tag("serial")\n@Execution(ExecutionMode.SAME_THREAD)\nvoid mustRunSequentially() { }\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-properties",children:"# Run only parallel tests\njunit.jupiter.includeTags=parallel\n"})}),"\n",(0,t.jsx)(n.h3,{id:"4-clean-up-resources",children:"4. Clean Up Resources"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"@AfterEach\nvoid cleanup() {\
1n    // Clean up test data\n    testDataService.deleteTestData(testId);\n}\n"})}),"\n",(0,t.jsx)(n.h3,{id:"5-document-thread-safety",children:"5. Document Thread Safety"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",children:"/**\n * Tests in this class modify global application state\n * and must run sequentially.\n */\n@Execution(ExecutionMode.SAME_THREAD)\nclass GlobalStateTests {\n    // ...\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"measuring-performance",children:"Measuring Performance"}),"\n",(0,t.jsx)(n.h3,{id:"before-parallel-execution",children:"Before Parallel Execution"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Total tests: 150\nExecution time: 25 minutes\n"})}),"\n",(0,t.jsx)(n.h3,{id:"after-parallel-execution-8-threads",children:"After Parallel Execution (8 threads)"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Total tests: 150\nExecution time: 4 minutes\nSpeedup: 6.25x\nEfficiency: 78%\n"})}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Calculate metrics:"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"Speedup = Sequential Time / Parallel Time\nEfficiency = Speedup / Number of Threads \xd7 100%\n"})}),"\n",(0,t.jsx)(n.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Return to the main ",(0,t.jsx)(n.a,{href:"junit5-tests",children:"JUnit 5 Guide"})]}),"\n",(0,t.jsxs)(n.li,{children:["Learn about ",(0,t.jsx)(n.a,{href:"junit5-tests#display-names-and-organization",children:"Test Organization"})]}),"\n",(0,t.jsxs)(n.li,{children:["Review ",(0,t.jsx)(n.a,{href:"junit5-tests#best-practices",children:"Best Practices"})]}),"\n",(0,t.jsxs)(n.li,{children:["Explore ",(0,t.jsx)(n.a,{href:"/docs/reporting/the_serenity_reports",children:"Serenity Reports"})]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"additional-resources",children:"Additional Resources"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"https://junit.org/junit5/docs/current/user-guide/#writing-tests-parallel-execution",children:"JUnit 5 Parallel Execution Docs"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"https://serenity-bdd.info",children:"Serenity BDD Performance Tips"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"https://jcip.net/",children:"Java Concurrency in Practice"})}),"\n"]})]})}function u(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453(e,n,i){i.d(n,{R:()=>r,x:()=>l});var s=i(6540);const t={},a=s.createContext(t);function r(e){const n=s.useContext(a);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.