---
title: Reqnroll C# BDD Selenium Testing Framework
description: Reqnroll BDD testing with Selenium in C#. The successor to SpecFlow for
  Gherkin-based testing. Run your tests on 6100+ real browsers and devices.
source_url:
  html: https://testingbot.com/support/web-automate/selenium/csharp/reqnroll
  md: https://testingbot.com/support/web-automate/selenium/csharp/reqnroll/index.md
---
# C# BDD Testing with Reqnroll

[Reqnroll](https://reqnroll.net/) is an open-source .NET test automation framework for Behavior-Driven Development (BDD). It is the community-maintained successor to SpecFlow and is fully compatible with Gherkin syntax.

Reqnroll works with all major .NET versions (.NET 6.0, 7.0, 8.0, 9.0) and integrates with popular test frameworks:

- NUnit
- xUnit
- MSTest
- TUnit

**Migrating from SpecFlow?** Reqnroll is based on the SpecFlow codebase and provides an easy migration path. See the [migration section](https://testingbot.com#migration) below.

## Installation

First, install the **Reqnroll for Visual Studio 2022** extension from the Visual Studio Marketplace to get syntax highlighting, navigation and project templates.

### Create a new project

Create a new test project and add the required packages:

    # Create a new NUnit test project
    dotnet new nunit -n ReqnrollTests
    cd ReqnrollTests
    
    # Add Reqnroll with NUnit integration
    dotnet add package Reqnroll.NUnit
    
    # Add Selenium WebDriver packages
    dotnet add package Selenium.WebDriver
    dotnet add package Selenium.Support

Or add these packages to your `.csproj` file:

    <ItemGroup>
      <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
      <PackageReference Include="NUnit" Version="4.1.0" />
      <PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
      <PackageReference Include="Reqnroll.NUnit" Version="2.3.0" />
      <PackageReference Include="Selenium.WebDriver" Version="4.27.0" />
      <PackageReference Include="Selenium.Support" Version="4.27.0" />
    </ItemGroup>

Alternative packages for other test frameworks:

- `Reqnroll.xUnit` - for xUnit 2.x
- `Reqnroll.xUnit.v3` - for xUnit 3.x
- `Reqnroll.MsTest` - for MSTest
- `Reqnroll.TUnit` - for TUnit

## Your first Reqnroll test

Reqnroll tests consist of three parts: a Feature file (Gherkin), Step Definitions (C#), and a Driver helper class.

### 1. Feature File

Create a `Features` folder and add `Search.feature`:

    Feature: Google Search
    
    Scenario: Search for TestingBot
      Given I am on the Google homepage
      When I search for "TestingBot"
      Then the page title should contain "TestingBot"
    
    Scenario Outline: Search on multiple browsers
      Given I am using <browser> on <platform>
      And I am on the Google homepage
      When I search for "TestingBot"
      Then the page title should contain "TestingBot"
    
      Examples:
        | browser | platform |
        | chrome | WIN10 |
        | firefox | WIN10 |
        | safari | TAHOE |

### 2. Driver Helper Class

Create a helper class to manage the WebDriver connection to TestingBot:

    using OpenQA.Selenium;
    using OpenQA.Selenium.Chrome;
    using OpenQA.Selenium.Firefox;
    using OpenQA.Selenium.Safari;
    using OpenQA.Selenium.Remote;
    
    namespace ReqnrollTests.Support;
    
    public class TestingBotDriver : IDisposable
    {
        public IWebDriver Driver { get; private set; }
        private bool _testPassed = true;
    
        public void Initialize(string browser = "chrome", string version = "latest", string platform = "WIN10")
        {
            DriverOptions options = browser.ToLower() switch
            {
                "firefox" => new FirefoxOptions(),
                "safari" => new SafariOptions(),
                _ => new ChromeOptions()
            };
    
            options.BrowserVersion = version;
            options.PlatformName = platform;
            options.AddAdditionalOption("tb:options", new Dictionary<string, object>
            {
                ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "",
                ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "",
                ["name"] = "Reqnroll Test"
            });
    
            Driver = new RemoteWebDriver(
                new Uri("https://hub.testingbot.com/wd/hub"),
                options
            );
        }
    
        public void MarkTestFailed() => _testPassed = false;
    
        public void Dispose()
        {
            if (Driver != null)
            {
                var status = _testPassed ? "passed" : "failed";
                ((IJavaScriptExecutor)Driver).ExecuteScript($"tb:test-result={status}");
                Driver.Dispose();
            }
        }
    }

### 3. Step Definitions

Create `StepDefinitions/SearchSteps.cs`:

    using OpenQA.Selenium;
    using Reqnroll;
    using ReqnrollTests.Support;
    
    namespace ReqnrollTests.StepDefinitions;
    
    [Binding]
    public class SearchSteps
    {
        private readonly TestingBotDriver _tbDriver;
    
        public SearchSteps(TestingBotDriver tbDriver)
        {
            _tbDriver = tbDriver;
        }
    
        [Given("I am on the Google homepage")]
        public void GivenIAmOnTheGoogleHomepage()
        {
            if (_tbDriver.Driver == null)
                _tbDriver.Initialize();
    
            _tbDriver.Driver.Navigate().GoToUrl("https://www.google.com");
        }
    
        [Given("I am using (.*) on (.*)")]
        public void GivenIAmUsingBrowserOnPlatform(string browser, string platform)
        {
            _tbDriver.Initialize(browser, "latest", platform);
        }
    
        [When("I search for {string}")]
        public void WhenISearchFor(string searchTerm)
        {
            var searchBox = _tbDriver.Driver.FindElement(By.Name("q"));
            searchBox.SendKeys(searchTerm);
            searchBox.Submit();
        }
    
        [Then("the page title should contain {string}")]
        public void ThenThePageTitleShouldContain(string expectedText)
        {
            // Wait for results to load
            Thread.Sleep(2000);
            Assert.That(_tbDriver.Driver.Title, Does.Contain(expectedText));
        }
    }

### 4. Hooks for Setup/Teardown

Create `Hooks/TestHooks.cs` to manage driver lifecycle:

    using Reqnroll;
    using ReqnrollTests.Support;
    
    namespace ReqnrollTests.Hooks;
    
    [Binding]
    public class TestHooks
    {
        private readonly TestingBotDriver _tbDriver;
    
        public TestHooks(TestingBotDriver tbDriver)
        {
            _tbDriver = tbDriver;
        }
    
        [AfterScenario]
        public void AfterScenario(ScenarioContext scenarioContext)
        {
            if (scenarioContext.TestError != null)
            {
                _tbDriver.MarkTestFailed();
            }
            _tbDriver.Dispose();
        }
    }

Run your tests with:

    TB_KEY=your_key TB_SECRET=your_secret dotnet test

## Specify Browsers & Devices

Configure browsers and platforms using Selenium 4's browser-specific options classes:

- `ChromeOptions` for Chrome
- `FirefoxOptions` for Firefox
- `EdgeOptions` for Microsoft Edge
- `SafariOptions` for Safari

Example using ChromeOptions:

    var options = new ChromeOptions();
    options.BrowserVersion = "latest";
    options.PlatformName = "WIN10";
    options.AddAdditionalOption("tb:options", new Dictionary<string, object>
    {
        ["key"] = "YOUR_TB_KEY",
        ["secret"] = "YOUR_TB_SECRET",
        ["name"] = "My Reqnroll Test"
    });
    
    var driver = new RemoteWebDriver(
        new Uri("https://hub.testingbot.com/wd/hub"),
        options
    );

To see how to configure different browsers and platforms, use the picker below:

  ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg) Windows 11 › ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg) Chrome 139 

Loading environments...

Please wait while we load the available browsers and platforms.

    

## Testing Internal Websites

Use [TestingBot Tunnel](https://testingbot.com/support/tunnel) to securely test internal or staged websites.

**1.** [Download the tunnel](https://testingbot.com/support/tunnel) and start it:

    java -jar testingbot-tunnel.jar key secret

**2.** Update your driver initialization to connect through the tunnel:

    // Connect through the tunnel instead of directly to TestingBot
    Driver = new RemoteWebDriver(
        new Uri("http://localhost:4445/wd/hub"),
        options
    );
    
    // Now you can access internal URLs in your tests
    Driver.Navigate().GoToUrl("http://internal.yourcompany.com");

## Run tests in Parallel

Reqnroll supports parallel test execution when using NUnit or xUnit as the test runner.

### NUnit Parallel Execution

Add to your `AssemblyInfo.cs` or any file:

    using NUnit.Framework;
    
    [assembly: Parallelizable(ParallelScope.Fixtures)]
    [assembly: LevelOfParallelism(5)]

Configure in `reqnroll.json`:

    {
      "$schema": "https://schemas.reqnroll.net/reqnroll-config-latest.json",
      "bindingCulture": {
        "name": "en-US"
      }
    }

### xUnit Parallel Execution

Add `xunit.runner.json`:

    {
      "parallelizeAssembly": true,
      "parallelizeTestCollections": true,
      "maxParallelThreads": 5
    }

### Queuing

Every TestingBot plan has a limit on parallel tests. If you exceed this limit, additional tests are queued (up to 6 minutes) and run as slots become available.

## Mark tests as passed/failed

Report test results to TestingBot using JavaScript execution in your `[AfterScenario]` hook:

    [Binding]
    public class TestHooks
    {
        private readonly TestingBotDriver _tbDriver;
    
        public TestHooks(TestingBotDriver tbDriver)
        {
            _tbDriver = tbDriver;
        }
    
        [AfterScenario]
        public void AfterScenario(ScenarioContext scenarioContext)
        {
            if (_tbDriver.Driver != null)
            {
                var status = scenarioContext.TestError == null ? "passed" : "failed";
                ((IJavaScriptExecutor)_tbDriver.Driver).ExecuteScript($"tb:test-result={status}");
                _tbDriver.Driver.Dispose();
            }
        }
    }

## Migrating from SpecFlow

Reqnroll is designed as a drop-in replacement for SpecFlow. Most projects can migrate with minimal changes:

### 1. Update NuGet Packages

    # Remove SpecFlow packages
    dotnet remove package SpecFlow
    dotnet remove package SpecFlow.NUnit
    
    # Add Reqnroll packages
    dotnet add package Reqnroll.NUnit

### 2. Update Namespaces

Replace `TechTalk.SpecFlow` with `Reqnroll` in your code:

    // Before (SpecFlow)
    using TechTalk.SpecFlow;
    
    // After (Reqnroll)
    using Reqnroll;

### 3. Update Configuration

Rename `specflow.json` to `reqnroll.json` and update the schema reference:

    {
      "$schema": "https://schemas.reqnroll.net/reqnroll-config-latest.json"
    }

### 4. Update Visual Studio Extension

Install the "Reqnroll for Visual Studio 2022" extension and uninstall the SpecFlow extension.

For a complete migration guide, see the [official SpecFlow to Reqnroll migration guide](https://reqnroll.net/news/2024/02/from-specflow-to-reqnroll-why-and-how/).

## Other C# Framework examples

- [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit)

An unit testing framework that is open source written in C#.

- [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit)

xUnit.net is a modern, extensible testing framework for .NET, widely used in the .NET ecosystem.

- [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest)

MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio.

- [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow)

SpecFlow (deprecated) - the predecessor to Reqnroll for BDD testing with Gherkin syntax.

### Looking for more help?

Have questions or need more information? Reach out via email or Slack.

[Email us](https://testingbot.com/contact/new)[Slack Join our Slack](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw)
