C# BDD Testing with Reqnroll
Reqnroll 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 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:
-
ChromeOptionsfor Chrome -
FirefoxOptionsfor Firefox -
EdgeOptionsfor Microsoft Edge -
SafariOptionsfor 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:
Testing Internal Websites
Use TestingBot Tunnel to securely test internal or staged websites.
1. Download the 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.
Other C# Framework examples
-
NUnit
An unit testing framework that is open source written in C#.
-
xUnit
xUnit.net is a modern, extensible testing framework for .NET, widely used in the .NET ecosystem.
-
MSTest
MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio.
-
SpecFlow
SpecFlow (deprecated) - the predecessor to Reqnroll for BDD testing with Gherkin syntax.