Skip to content

[dotnet] [test] Parallelize internal testing - #18110

Merged
nvborisenko merged 4 commits into
SeleniumHQ:trunkfrom
nvborisenko:dotnet-test-parallelize
Oct 1, 2026
Merged

nvborisenko merged 4 commits into
SeleniumHQ:trunkfrom
nvborisenko:dotnet-test-parallelize

Conversation

@nvborisenko

@nvborisenko nvborisenko commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Enable parallel tests execution per fixture.

Before (Chrome):

Test run summary: Failed! - bin/Debug/net10.0/WebDriver.Tests.dll (net10.0|arm64)
  total: 1390
  failed: 2
  succeeded: 1282
  skipped: 106
  duration: 5m 18s 273ms

After (Chrome):

Test run summary: Failed! - bin/Debug/net10.0/WebDriver.Tests.dll (net10.0|arm64)
  total: 1390
  failed: 4
  succeeded: 1280
  skipped: 106
  duration: 1m 42s 299ms

Firefox (before/after):

duration: 8m 05s 562ms
duration: 3m 34s 300ms

🔗 Related Issues

Contributes to #15536

💥 What does this PR do?

This pull request refactors the test infrastructure to improve driver management and parallelization in the .NET Selenium test suite. The main changes include introducing a new DriverFactory for driver creation, removing driver lifecycle management from EnvironmentManager, and enabling parallel test execution at the fixture level. Several test fixtures and driver configuration classes are updated to use the new approach.

Test Infrastructure Refactoring:

  • Introduced a new DriverFactory class that handles driver instantiation, including resolving driver types and managing headless options, replacing the previous approach in EnvironmentManager. This centralizes and simplifies driver creation logic. [1] [2] [3] [4] [5] [6]
  • Updated driver configuration classes (e.g., DefaultSafariDriver, DevChannelChromeDriver, etc.) to reference DriverFactory.CreateDriver(options) instead of the old EnvironmentManager.Instance.CreateDriverInstance(options). [1] [2] [3] [4] [5] [6] [7] [8] [9]

Driver Lifecycle Management:

  • Moved responsibility for creating, disposing, and refreshing drivers from EnvironmentManager to DriverTestFixture and its subclasses, introducing new helper methods like CreateDriverInstance, CloseDriver, and CreateFreshDriver. [1] [2]
  • Simplified the NeedsFreshDriverAttribute to use the new fixture-based driver management rather than interacting with EnvironmentManager directly.

Parallelization Improvements:

  • Enabled parallel test execution at the fixture level by adding [assembly: Parallelizable(ParallelScope.Fixtures)] to relevant test assemblies. [1] [2]

Other Notable Changes:

  • Refactored the WaitFor<T> method in DriverTestFixture to use DefaultWait<Func<T>> instead of WebDriverWait, making it independent of the fixture driver and more flexible.
  • Removed unused or redundant code from EnvironmentManager, including driver instance storage and event handling, making it a stateless provider of environment configuration. [1] [2] [3] [4]

These changes collectively modernize the test infrastructure, improve reliability for parallel test runs, and make driver management more modular and maintainable.

🔧 Implementation Notes

  • BaseFixture is stateful (run new driver one time)
  • Parallelizable by default

🤖 AI assistance

  • No substantial AI assistance used
  • AI assisted (complete below)
    • Tool(s):
    • What was generated:
    • I reviewed all AI output and can explain the change

💡 Additional Considerations

Here we don't enable parallelization at test level. At fixture level is good enough.

🔄 Types of changes

  • Cleanup (formatting, renaming)

@selenium-ci selenium-ci added C-dotnet .NET Bindings B-support Issue or PR related to support classes labels Oct 1, 2026
@selenium-ci

Copy link
Copy Markdown
Member

Thank you, @nvborisenko for this code suggestion.

The support packages contain example code that many users find helpful, but they do not necessarily represent
the best practices for using Selenium, and the Selenium team is not currently merging changes to them.

After reviewing the change, unless it is a critical fix or a feature that is needed for Selenium
to work, we will likely close the PR.

We actively encourage people to add the wrapper and helper code that makes sense for them to their own frameworks.
If you have any questions, please contact us

@nvborisenko
nvborisenko marked this pull request as draft October 1, 2026 15:11
@qodo-code-review

qodo-code-review Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Parallelize .NET test fixtures with fixture-owned browser drivers

🧪 Tests ✨ Enhancement 🕐 40+ Minutes

Grey Divider

AI Description

• Run .NET test fixtures concurrently to reduce browser suite execution time.
• Move driver ownership from shared environment state into individual fixtures.
• Keep single-session browsers and tests with shared resources sequential.
Diagram

graph TD
  Guards["Serial guards"] --> NUnit["NUnit scheduling"] --> Fixture["Test fixture"] --> Factory["Driver factory"] --> Browser["Browser session"]
  Environment["Environment config"] --> Factory
  Special["Specialized tests"] --> Fixture
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Thread-local drivers in EnvironmentManager
  • ➕ Would require fewer changes to existing test call sites.
  • ➖ Retains implicit driver ownership and makes teardown and additional-driver behavior harder to reason about.

Recommendation: Prefer fixture-owned drivers: their lifecycle matches NUnit's parallel scheduling and keeps the environment manager limited to shared configuration. Preserve the explicit serial guards for browsers and tests that cannot safely share concurrent execution.

Files changed (33) +193 / -156

Enhancement (1) +45 / -0
SingleSessionBrowserAttribute.csAdd browser-aware sequential scheduling +45/-0

Add browser-aware sequential scheduling

• Adds an assembly attribute that sets NUnit's worker level to zero when the active browser is in its single-session list.

dotnet/test/testing.nunit/SingleSessionBrowserAttribute.cs

Refactor (5) +69 / -90
AssemblyFixtureBase.csLeave driver teardown to individual fixtures +0/-1

Leave driver teardown to individual fixtures

• Removes assembly-wide driver closure while retaining shared server shutdown.

dotnet/test/testing.nunit/AssemblyFixtureBase.cs

DriverTestFixture.csOwn browser drivers per test fixture +31/-15

Own browser drivers per test fixture

• Creates a factory and driver at fixture setup, disposes the driver at teardown, and exposes fixture-local replacement and creation helpers. Changes waiting to avoid depending on a driver that specialized tests may have closed.

dotnet/test/testing.nunit/DriverTestFixture.cs

DriverFactory.csMove configured driver resolution into DriverFactory +25/-12

Move configured driver resolution into DriverFactory

• Constructs factories from environment settings, caches resolved driver types concurrently, and creates drivers with optional options. Headless configuration is read from the factory instance rather than the environment singleton during creation.

dotnet/test/testing.nunit/Environment/DriverFactory.cs

EnvironmentManager.csRestrict EnvironmentManager to shared configuration +11/-57

Restrict EnvironmentManager to shared configuration

• Removes its driver instance, factory, creation APIs, and driver-starting event. Exposes driver configuration for fixture-owned factories and initializes the singleton through Lazy<T>.

dotnet/test/testing.nunit/Environment/EnvironmentManager.cs

NeedsFreshDriverAttribute.csRefresh the owning fixture's driver +2/-5

Refresh the owning fixture's driver

• Routes before- and after-test driver replacement through the fixture instead of shared environment state.

dotnet/test/testing.nunit/NeedsFreshDriverAttribute.cs

Tests (17) +68 / -55
AssemblyTeardown.csEnable fixture parallelism in remote tests +3/-0

Enable fixture parallelism in remote tests

• Adds assembly-level fixture parallelism and serial execution for Safari and IE configurations.

dotnet/test/remote/AssemblyTeardown.cs

RemoteWebDriverSpecificTests.csClose the fixture driver before remote session testing +1/-1

Close the fixture driver before remote session testing

• Replaces shared-environment driver closure with fixture-local cleanup.

dotnet/test/remote/RemoteWebDriverSpecificTests.cs

AssemblyFixture.csEnable guarded parallelism in support tests +3/-0

Enable guarded parallelism in support tests

• Allows support fixtures to run concurrently except when the active browser is Safari or IE.

dotnet/test/support/AssemblyFixture.cs

AlertsTests.csClose the fixture driver during alert shutdown testing +1/-2

Close the fixture driver during alert shutdown testing

• Uses fixture-local cleanup when testing driver closure with an alert present.

dotnet/test/webdriver/AlertsTests.cs

AssemblyFixture.csEnable guarded parallelism in WebDriver tests +3/-0

Enable guarded parallelism in WebDriver tests

• Enables parallel execution across WebDriver fixtures and disables it for Safari and IE configurations.

dotnet/test/webdriver/AssemblyFixture.cs

BiDiFixture.csCreate BiDi drivers through DriverFactory +1/-1

Create BiDi drivers through DriverFactory

• Replaces EnvironmentManager driver creation with a configured factory for BiDi setup.

dotnet/test/webdriver/BiDi/BiDiFixture.cs

CookieImplementationTests.csRefresh cookie-test drivers within their fixture +1/-2

Refresh cookie-test drivers within their fixture

• Uses the fixture helper to replace a driver when clearing cookies requires a new session.

dotnet/test/webdriver/CookieImplementationTests.cs

CorrectEventFiringTests.csCreate additional event-test drivers locally +2/-2

Create additional event-test drivers locally

• Uses the fixture's factory to create second drivers for non-topmost-window scenarios.

dotnet/test/webdriver/CorrectEventFiringTests.cs

DevToolsTestFixture.csManage DevTools fixture sessions locally +6/-3

Manage DevTools fixture sessions locally

• Recreates a missing fixture driver during setup and closes it locally when a DevTools session ends.

dotnet/test/webdriver/DevTools/DevToolsTestFixture.cs

DownloadsTests.csUse fixture-local drivers in download tests +3/-4

Use fixture-local drivers in download tests

• Moves driver closure, replacement, and configured download-driver creation to fixture helpers.

dotnet/test/webdriver/DownloadsTests.cs

FirefoxDriverServiceTests.csRun Firefox service tests sequentially +1/-0

Run Firefox service tests sequentially

• Marks the fixture nonparallelizable to avoid concurrent service-test interference.

dotnet/test/webdriver/Firefox/FirefoxDriverServiceTests.cs

LogTests.csRun logging tests sequentially +1/-0

Run logging tests sequentially

• Marks logging tests nonparallelizable to avoid interference through shared logging state.

dotnet/test/webdriver/Internal/Logging/LogTests.cs

PageLoadingTests.csIsolate page-loading driver replacement +6/-4

Isolate page-loading driver replacement

• Restores a missing fixture driver during setup and creates strategy-specific local drivers without changing another fixture's session.

dotnet/test/webdriver/PageLoadingTests.cs

ProxySettingTests.csScope proxy driver hooks to the fixture factory +10/-7

Scope proxy driver hooks to the fixture factory

• Attaches the IE clean-session hook to this fixture's factory rather than a global event. Creates proxy-configured drivers and closes the original driver through fixture helpers.

dotnet/test/webdriver/ProxySettingTests.cs

SessionHandlingTests.csIsolate session lifecycle tests +18/-20

Isolate session lifecycle tests

• Replaces shared-environment driver creation and closure with fixture-local helpers across session disposal and restart cases.

dotnet/test/webdriver/SessionHandlingTests.cs

TimeoutDriverOptionsTests.csCreate timeout-test drivers with a local factory +5/-4

Create timeout-test drivers with a local factory

• Adds a factory to the fixture and uses it for drivers created with timeout options.

dotnet/test/webdriver/TimeoutDriverOptionsTests.cs

UnexpectedAlertBehaviorTests.csIsolate unexpected-alert driver replacement +3/-5

Isolate unexpected-alert driver replacement

• Uses fixture helpers to close and restore its driver and create sessions with custom prompt behavior.

dotnet/test/webdriver/UnexpectedAlertBehaviorTests.cs

Documentation (9) +9 / -9
DefaultSafariDriver.csDocument Safari factory constructor use +1/-1

Document Safari factory constructor use

• Updates the constructor comment to identify DriverFactory as its dynamic caller.

dotnet/test/testing.nunit/DriverConfigs/DefaultSafariDriver.cs

DevChannelChromeDriver.csDocument development Chrome factory constructor use +1/-1

Document development Chrome factory constructor use

• Updates the options-constructor comment to reference DriverFactory.

dotnet/test/testing.nunit/DriverConfigs/DevChannelChromeDriver.cs

DevChannelEdgeDriver.csDocument development Edge factory constructor use +1/-1

Document development Edge factory constructor use

• Updates the options-constructor comment to reference DriverFactory.

dotnet/test/testing.nunit/DriverConfigs/DevChannelEdgeDriver.cs

EdgeInternetExplorerModeDriver.csDocument IE-mode factory constructor use +1/-1

Document IE-mode factory constructor use

• Updates the options-constructor comment to reference DriverFactory.

dotnet/test/testing.nunit/DriverConfigs/EdgeInternetExplorerModeDriver.cs

NightlyChannelFirefoxDriver.csDocument nightly Firefox factory constructor use +1/-1

Document nightly Firefox factory constructor use

• Updates the options-constructor comment to reference DriverFactory.

dotnet/test/testing.nunit/DriverConfigs/NightlyChannelFirefoxDriver.cs

SafariTechnologyPreviewDriver.csDocument Safari Technology Preview factory use +1/-1

Document Safari Technology Preview factory use

• Updates the options-constructor comment to reference DriverFactory.

dotnet/test/testing.nunit/DriverConfigs/SafariTechnologyPreviewDriver.cs

StableChannelChromeDriver.csDocument stable Chrome factory constructor use +1/-1

Document stable Chrome factory constructor use

• Updates the options-constructor comment to reference DriverFactory.

dotnet/test/testing.nunit/DriverConfigs/StableChannelChromeDriver.cs

StableChannelEdgeDriver.csDocument stable Edge factory constructor use +1/-1

Document stable Edge factory constructor use

• Updates the options-constructor comment to reference DriverFactory.

dotnet/test/testing.nunit/DriverConfigs/StableChannelEdgeDriver.cs

StableChannelFirefoxDriver.csDocument stable Firefox factory constructor use +1/-1

Document stable Firefox factory constructor use

• Updates the options-constructor comment to reference DriverFactory.

dotnet/test/testing.nunit/DriverConfigs/StableChannelFirefoxDriver.cs

Other (1) +2 / -2
dotnet_nunit_test_suite.bzlMark IE and Safari suites exclusive locally +2/-2

Mark IE and Safari suites exclusive locally

• Adds Bazel tags preventing local parallel execution of IE and Safari test targets, whose browsers cannot run concurrent sessions.

dotnet/private/dotnet_nunit_test_suite.bzl

@nvborisenko
nvborisenko marked this pull request as ready for review October 1, 2026 15:52
@nvborisenko
nvborisenko requested a balanced review from Copilot October 1, 2026 15:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Blanket parallelization races process-global logging tests and attempts unsupported concurrent Safari sessions.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Refactors .NET test driver ownership to support fixture-level parallel execution.

Changes:

  • Moves driver creation into DriverFactory and lifecycle management into fixtures.
  • Enables parallel fixture execution across test assemblies.
  • Migrates tests and wait helpers to fixture-local drivers.

Risk: Test infrastructure only; no cross-binding API impact.

File Description
dotnet/​test/​webdriver/​UnexpectedAlertBehaviorTests.cs Uses fixture-local lifecycle helpers.
dotnet/​test/​webdriver/​TimeoutDriverOptionsTests.cs Creates drivers through DriverFactory.
dotnet/​test/​webdriver/​SessionHandlingTests.cs Migrates session lifecycle handling.
dotnet/​test/​webdriver/​ProxySettingTests.cs Hooks driver-start events per fixture.
dotnet/​test/​webdriver/​PageLoadingTests.cs Uses fixture-local and additional drivers.
dotnet/​test/​webdriver/​DownloadsTests.cs Migrates custom driver lifecycle.
dotnet/​test/​webdriver/​DevTools/​DevToolsTestFixture.cs Manages DevTools drivers per fixture.
dotnet/​test/​webdriver/​CorrectEventFiringTests.cs Creates secondary drivers via fixture helper.
dotnet/​test/​webdriver/​CookieImplementationTests.cs Refreshes the fixture-owned driver.
dotnet/​test/​webdriver/​BiDi/​BiDiFixture.cs Uses the new factory for BiDi drivers.
dotnet/​test/​webdriver/​AssemblyFixture.cs Enables fixture-level parallelism.
dotnet/​test/​webdriver/​AlertsTests.cs Uses fixture-local driver closure.
dotnet/​test/​testing.nunit/​NeedsFreshDriverAttribute.cs Refreshes drivers through fixture APIs.
dotnet/​test/​testing.nunit/​Environment/​EnvironmentManager.cs Removes shared driver state.
dotnet/​test/​testing.nunit/​Environment/​DriverFactory.cs Centralizes cached driver resolution and creation.
dotnet/​test/​testing.nunit/​DriverTestFixture.cs Owns driver factory and lifecycle per fixture.
dotnet/​test/​testing.nunit/​DriverConfigs/​StableChannelFirefoxDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​DriverConfigs/​StableChannelEdgeDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​DriverConfigs/​StableChannelChromeDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​DriverConfigs/​SafariTechnologyPreviewDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​DriverConfigs/​NightlyChannelFirefoxDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​DriverConfigs/​EdgeInternetExplorerModeDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​DriverConfigs/​DevChannelEdgeDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​DriverConfigs/​DevChannelChromeDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​DriverConfigs/​DefaultSafariDriver.cs Updates factory reference comment.
dotnet/​test/​testing.nunit/​AssemblyFixtureBase.cs Removes assembly-wide driver cleanup.
dotnet/​test/​support/​AssemblyFixture.cs Enables fixture-level parallelism.
dotnet/​test/​remote/​RemoteWebDriverSpecificTests.cs Uses fixture-local driver closure.
dotnet/​test/​remote/​AssemblyTeardown.cs Enables fixture-level parallelism.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread dotnet/test/webdriver/AssemblyFixture.cs
@nvborisenko
nvborisenko marked this pull request as draft October 1, 2026 16:03
@nvborisenko
nvborisenko marked this pull request as ready for review October 1, 2026 16:27
@nvborisenko
nvborisenko requested a balanced review from Copilot October 1, 2026 16:27
@qodo-code-review

qodo-code-review Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Code Review by Qodo

Grey Divider

Sorry, something went wrong

We weren't able to complete the code review on our side. Please try again manually by commenting /agentic_review on this PR.

Grey Divider

Qodo Logo

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Suite-wide parallel scheduling and driver lifecycle changes have broad concurrency implications requiring final human validation.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@nvborisenko

Copy link
Copy Markdown
Member Author

Good big step!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-support Issue or PR related to support classes C-dotnet .NET Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants