Cross-browser testing in Selenium C# ensures applications work consistently across different browsers and versions. It verifies functionality, layout, and performance so users get the same experience whether they use Chrome, Firefox, or Edge.
With Selenium and C#, teams can automate tests efficiently, set up drivers, run tests in parallel with NUnit, and integrate them into CI/CD pipelines for continuous feedback.
This article explains how to set up Selenium C# for cross-browser testing, manage drivers, configure NUnit, handle pipelines, and apply best practices.
Cross-browser testing in Selenium C# checks how an application behaves across different browsers. It helps detect differences in rendering engines, JavaScript execution, and element interaction that often lead to layout issues or broken workflows. These checks ensure the application works the same way for every user.
Selenium WebDriver supports browser-specific drivers like ChromeDriver, GeckoDriver, and EdgeDriver. In C#, NUnit makes it possible to parameterize and run the same test across multiple browsers efficiently, without duplicating code. This improves coverage while keeping the framework maintainable.
Before you start, make sure you have:
Having these basics in place reduces flaky tests and makes it easier to integrate with CI/CD pipelines.
Cross-browser testing in C# begins with a reliable test environment. You need Visual Studio for development, Selenium WebDriver for browser automation, and NUnit for test execution. Using NuGet, you can add these dependencies directly to your project, which keeps package management consistent.
A practical setup involves:
Here’s a minimal example of a base class in C#:
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Edge;
namespace CrossBrowserTests
{
public class BaseTest
{
protected IWebDriver driver;
[SetUp]
public void Setup([Values("chrome", "firefox", "edge")] string browser)
{
switch (browser.ToLower())
{
case "chrome":
driver = new ChromeDriver();
break;
case "firefox":
driver = new FirefoxDriver();
break;
case "edge":
driver = new EdgeDriver();
break;
}
driver.Manage().Window.Maximize();
}
[TearDown]
public void Cleanup()
{
driver.Quit();
}
}
}
This structure ensures that every test run starts with a fresh browser instance and ends with proper cleanup. It also makes it easier to extend test cases to multiple browsers without duplicating logic.
When scaling cross-browser tests in Selenium C#, managing multiple drivers efficiently is essential. Hardcoding paths for ChromeDriver, GeckoDriver, or EdgeDriver quickly become unmanageable. A better approach is to centralize driver configuration and load the required driver dynamically.
Two common strategies are:
Here’s an example of a simple driver factory in C#:
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Edge;
namespace CrossBrowserTests
{
public static class DriverFactory
{
public static IWebDriver GetDriver(string browser)
{
return browser.ToLower() switch
{
"chrome" => new ChromeDriver(),
"firefox" => new FirefoxDriver(),
"edge" => new EdgeDriver(),
_ => throw new ArgumentException("Browser not supported: " + browser)
};
}
}
}
Then in your test class, you can call:
driver = DriverFactory.GetDriver("chrome");
This avoids repetitive setup code and makes it easy to switch browsers through a single parameter. For larger projects, you can extend the factory to include options like headless mode, custom profiles, or remote WebDriver execution with Selenium Grid.
Parallel test execution requires three things: configure NUnit to run workers, make sure each test has its own WebDriver instance, and avoid shared state between threads.
1. Set NUnit assembly settings
Define the number of parallel workers for the entire test run. Add this attribute in AssemblyInfo.cs or any compiled source file:
using NUnit.Framework;
[assembly: LevelOfParallelism(4)]
Adjust 4 to match the number of cores on your CI agent or local machine.
2. Use NUnit parallel attributes
Mark tests or fixtures for parallel execution with the right scope:
Example:
[TestFixture]
[Parallelizable(ParallelScope.Children)]
public class SampleTests : BaseTest
{
// tests here
}
3. Ensure thread-safe WebDriver instances
Never share a single IWebDriver across threads. Use ThreadLocal<IWebDriver> so each test thread has its own instance.
Example base class:
public class BaseTest
{
private static ThreadLocal<IWebDriver> _threadDriver = new ThreadLocal<IWebDriver>();
protected IWebDriver driver => _threadDriver.Value;
[SetUp]
public void Setup([Values("chrome","firefox","edge")] string browser)
{
_threadDriver.Value = DriverFactory.GetDriverWithOptions(browser);
driver.Manage().Window.Maximize();
}
[TearDown]
public void Cleanup()
{
try { _threadDriver.Value?.Quit(); }
finally { _threadDriver.Value = null; }
}
}
DriverFactory.GetDriverWithOptions should return a fresh driver instance configured for the requested browser.
Cross-browser tests are most valuable when they run automatically during every build. Integrating Selenium C# tests with a CI/CD pipeline ensures that browser compatibility is validated before changes reach production.
1. Add test execution to your CI pipeline
Most CI/CD tools (GitHub Actions, Azure DevOps, Jenkins, GitLab) let you add a test stage. This stage should install drivers, restore NuGet packages, and run NUnit tests.
2. Install browsers and drivers on the agent
Make sure the CI agent has Chrome, Firefox, and Edge available. Use pre-installed drivers or download them as part of the pipeline. For example, in GitHub Actions:
- name: Setup ChromeDriver
uses: nanasess/setup-chromedriver@v2
3. Run NUnit tests with dotnet
Execute your cross-browser tests using the .NET test runner:
dotnet test CrossBrowserTests.csproj --logger "trx"
4. Publish test results
Store the NUnit test results so the CI system can display them in the build report. For Azure DevOps:
- task: PublishTestResults@2
inputs:
testResultsFormat: NUnit
testResultsFiles: '**/TestResult.xml'
5. Scale with Selenium Grid or cloud providers
For large projects, integrate Selenium Grid or a cloud service (like BrowserStack) to run tests across many browsers and OS combinations simultaneously.
Here’s a ready-to-use GitHub Actions workflow that runs your Selenium C# cross-browser tests with a browser matrix. It assumes your test setup reads the browser from the BROWSER environment variable (or uses a driver manager library at runtime). Short prelude, then the YAML.
Use this as /.github/workflows/crossbrowser-tests.yml
name: Cross-browser Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
browser: [ chrome, firefox, edge ]
dotnet-version: [ '7.0' ]
env:
# optional: override if needed
TEST_RESULTS_DIR: test-results
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Restore NuGet packages
run: dotnet restore
- name: Build
run: dotnet build --configuration Release
# optional: ensure ChromeDriver available when running chrome
- name: Setup ChromeDriver
if: matrix.browser == 'chrome'
uses: nanasess/setup-chromedriver@v2
with:
chromedriver-version: latest
# if you use a runtime driver manager inside tests (recommended),
# you can skip extra driver install steps. Otherwise add similar
# steps for geckodriver or edgedriver as needed.
- name: Run tests on ${{ matrix.browser }}
env:
BROWSER: ${{ matrix.browser }}
DOTNET_CLI_TELEMETRY_OPTOUT: 1
run: |
mkdir -p $TEST_RESULTS_DIR
dotnet test ./CrossBrowserTests/CrossBrowserTests.csproj \
--configuration Release \
--logger "trx;LogFileName=${{ matrix.browser }}.trx" \
--results-directory $TEST_RESULTS_DIR
- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.browser }}
path: ${{ env.TEST_RESULTS_DIR }}/*${{ matrix.browser }}*.trx
Notes and quick tips
Cross-browser testing with Selenium C# introduces issues that teams must plan for:
A reliable framework requires specific technical practices rather than generic guidelines:
Cross-browser testing in Selenium C# is not limited to running scripts on Chrome, Firefox, or Edge. A strong framework must handle locator differences, keep drivers in sync, and support parallel execution to avoid flakiness. NUnit with a driver factory and parameterized execution provides that foundation.
Local drivers only cover the browsers installed on your machine, and they cannot replicate older versions, multiple operating systems, or mobile environments. BrowserStack removes these limits by giving you instant access to 3,500+ real browsers and devices in the cloud. With built-in parallel execution, video recordings, screenshots, and detailed logs, it lets you validate C# tests at scale and debug issues faster than maintaining your own infrastructure.
Run Selenium Tests on Cloud
Get visual proof, steps to reproduce and technical logs with one click
Continue reading
Try Bird on your next bug - you’ll love it
“Game changer”
Julie, Head of QA
Try Bird later, from your desktop