Example Gherkin-to-CSharp Step Definitions
The following uses Reqnroll examples, however this is idential when using SpecFlow.
Here’s a clear, practical explanation of how Gherkin feature files map to C# step definitions (using SpecFlow/Reqnroll, since Reqnroll is the modern fork of SpecFlow).
Basic Gherkin → C# Mapping
Gherkin (Feature File)
Feature: Calculator
In order to avoid silly mistakes
As a maths student
I want to use a calculator
Scenario: Add two numbers
Given I have entered 50 into the calculator
And I have entered 70 into the calculator
When I press add
Then the result should be 120
C# Step Definitions (Reqnroll/SpecFlow)
using Reqnroll;
[Binding]
public class CalculatorSteps
{
private readonly Calculator _calculator = new();
private int _result;
[Given(@"I have entered (.*) into the calculator")]
public void GivenIHaveEnteredNumber(int number)
{
_calculator.Enter(number);
}
[When(@"I press add")]
public void WhenIPressAdd()
{
_result = _calculator.Add();
}
[Then(@"the result should be (.*)")]
public void ThenTheResultShouldBe(int expected)
{
Assert.Equal(expected, _result);
}
}
Notes
- Step attributes:
[Given],[When],[Then]map directly to steps in the Gherkin file. - Regex patterns inside the attributes capture values from the Gherkin step.
- Step classes must be decorated with
[Binding].
Example with Tables
Gherkin
Scenario: Create a user
Given I enter the following details
| Name | Age |
| Mark | 30 |
When I submit the form
Then the user should be created
C# Step Definition
[Given(@"I enter the following details")]
public void GivenIEnterDetails(Table table)
{
var user = table.CreateInstance<User>();
_context.User = user;
}
Reqnroll/SpecFlow automatically binds the table to a C# object using the headers.
Example with Scenario Outline
Gherkin
Scenario Outline: Multiplying numbers
Given I have entered <x> into the calculator
And I have entered <y> into the calculator
When I press multiply
Then the result should be <result>
Examples:
| x | y | result |
| 2 | 3 | 6 |
| 4 | 5 | 20 |
C# Step Definitions
Same as before — the placeholders are just passed into the regex.
Tips for Structuring Steps in C#
- Use step re-use to avoid repetition - If two Gherkin steps are similar, make one step regex broader.
- Keep logic out of step definitions - Steps should call into domain/service classes.
- Use DI - Reqnroll supports dependency injection via constructor injection in
[Binding]classes. - Avoid over-matching regex - Prefer explicit patterns:
[Given(@"I have entered (\d+) into the calculator")]
Drawbacks & Common Mistakes
| Issue | Description |
|---|---|
| Overuse of regex | Makes steps fragile and hard to read. |
| Putting business logic inside step definitions | Leads to duplication and hard-to-maintain automation code. |
| Too many step definitions | Good Gherkin design avoids repeating the same sentence many times. |
| Using steps like UI scripts | Steps should be behaviour-oriented, not pixel-oriented. |