Background
In the Specflow project, this given combination causes the problem:
- In StepDefinition's constructor: Initialization of object whose constructor contains a call to a method which has an 'async' modifier.
- A method in StepDefinition is associated/declared with the [BeforeScenario] and/or [Before] attribute and it also has an 'async' modifier.
When this deadly combination is applied to the Specflow project, every time upon the test execution a deadlock problem arises.
Question
Why is this happening? And how to overcome this issue, even by maintaining the above-mentioned combination.
Demo code
Calculator.feature
Feature: Calculator

Simple calculator for adding **two** numbers
Link to a feature: [Calculator]($projectname$/Features/Calculator.feature)
***Further read***: **[Learn more about how to generate Living Documentation](https://docs.specflow.org/projects/specflow-livingdoc/en/latest/LivingDocGenerator/Generating-Documentation.html)**
@mytag
Scenario: Add two numbers
Given the first number is 50
And the second number is 70
When the two numbers are added
Then the result should be 120
Calculator.cs
namespace CalculatorSpec;
internal class Calculator
{
internal int FirstNumber { get; set; }
internal int SecondNumber { get; set; }
internal int Total { get; private set; }
internal Calculator()
{
var printResult = "Calculator async started!".PrintAsync().GetAwaiter().GetResult();
if (printResult)
return;
throw new Exception("Sync execution exception!");
}
internal void Add() => Total = FirstNumber + SecondNumber;
}
Printing.cs
namespace CalculatorSpec;
public static class Printing
{
internal static async Task<bool> PrintAsync(this string message)
{
var task = new Task(() =>
{
Thread.Sleep(100);
Console.WriteLine(message);
});
task.Start();
await task;
return true;
}
}
CalculatorStepDefinitions.cs
using NUnit.Framework;
using TechTalk.SpecFlow.Infrastructure;
namespace CalculatorSpec;
[Binding]
public sealed class CalculatorStepDefinitions
{
private readonly ISpecFlowOutputHelper outputHelper;
private readonly Calculator calculator;
public CalculatorStepDefinitions(ISpecFlowOutputHelper specFlowOutputHelperHelper)
{
outputHelper = specFlowOutputHelperHelper;
calculator = new Calculator(); // Deadlock occurs
}
[Given("the first number is (.*)")]
public void GivenTheFirstNumberIs(int number)
{
calculator.FirstNumber = number;
}
[Given("the second number is (.*)")]
public void GivenTheSecondNumberIs(int number)
{
calculator.SecondNumber = number;
}
[When("the two numbers are added")]
public void WhenTheTwoNumbersAreAdded()
{
calculator.Add();
}
[Then("the result should be (.*)")]
public void ThenTheResultShouldBe(int result)
{
Assert.That(calculator.Total, Is.EqualTo(result));
}
[BeforeScenario]
public async Task BeforeScenario(ScenarioContext scenarioContext)
{
await "Execute print async".PrintAsync();
outputHelper.WriteLine("Started Scenario: " + scenarioContext.ScenarioInfo.Title);
}
[AfterScenario]
public void AfterScenario(ScenarioContext scenarioContext)
{
outputHelper.WriteLine("Completed Scenario: " + scenarioContext.ScenarioInfo.Title);
}
}
Tip
If I remove the async modifier from the method which is declared with [BeforeScenario] attribute, and also comment out the code block that awaits due to await keyword, then the problem is fixed. See below:
[BeforeScenario]
public /* async Task */ void BeforeScenario(ScenarioContext scenarioContext)
{
// await "Execute print async".PrintAsync();
outputHelper.WriteLine("Started Scenario: " + scenarioContext.ScenarioInfo.Title);
}
Environment
- .NET: 6.0.300
- SpecFlow: 3.9.22
- NUnit: 3.13.2