BDDfy is the simplest BDD (Behavior-Driven Development) framework for .NET. It turns your test classes into living documentation with human-readable reports — no special test runners or DSL files required.
Install via NuGet:
dotnet add package TestStack.BDDfyOr via the Package Manager Console:
Install-Package TestStack.BDDfyBDDfy works with any test framework — xUnit, NUnit, MSTest — or no framework at all.
The fastest way to write a BDDfy test is using method naming conventions. Name your methods with Given/When/Then prefixes and call this.BDDfy():
using Xunit;
using TestStack.BDDfy;
public class ShouldBeAbleToReturnItem
{
void GivenTheItemWasPurchasedRecently()
{
// arrange
}
void WhenTheCustomerReturnsTheItem()
{
// act
}
void ThenTheItemShouldBeAccepted()
{
// assert
}
[Fact]
public void Execute()
{
this.BDDfy();
}
}When you run this test, BDDfy automatically:
- Discovers steps by scanning method names for Given/When/Then prefixes
- Executes them in the correct order
- Produces a console report and an HTML report
Console output:
Scenario: Should be able to return item
Given the item was purchased recently
When the customer returns the item
Then the item should be accepted
BDDfy converts your method names into readable step titles using a humanizer. It supports:
- PascalCase:
GivenTheCardIsValid→ "Given the card is valid" - Underscored:
Given_the_card_is_valid→ "Given the card is valid" - camelCase:
givenTheCardIsValid→ "Given the card is valid"
Supported prefixes: Given, AndGiven, When, AndWhen, Then, AndThen, But.
BDDfy offers two main approaches to defining scenarios:
Steps are discovered automatically from method names or [Given]/[When]/[Then] attributes. Best for simple, self-contained scenarios.
[Fact]
public void Execute()
{
this.BDDfy();
}→ Full Reflective API documentation
Steps are declared using a fluent builder with lambda expressions. Best when you need explicit control over step ordering, titles, or reuse.
[Fact]
public void Execute()
{
this.Given(s => s.TheCardIsDisabled())
.When(s => s.TheAccountHolderRequestsCash(20))
.Then(s => s.TheAtmRetainsTheCard())
.BDDfy();
}→ Full Fluent API documentation
By default, BDDfy generates:
- Console report — printed to standard output after each scenario
- HTML report — a standalone HTML file written to your output directory after all tests complete
→ Full Reporters documentation
You can group scenarios under a user story using the [Story] attribute:
[Story(
AsA = "As an account holder",
IWant = "I want to withdraw cash from an ATM",
SoThat = "So that I can get money when the bank is closed")]
public class AccountHasInsufficientFund
{
// steps...
[Fact]
public void Execute()
{
this.BDDfy();
}
}You don't need a story. If you omit the [Story] attribute, BDDfy uses the namespace as a grouping mechanism in reports:
public class CanWorkWithoutAStory
{
void Given_no_story_is_provided() { }
void When_we_BDDfy_the_class() { }
void Then_the_namespace_is_used_in_the_report() { }
[Fact]
public void RunTestWithoutAStory()
{
this.BDDfy();
}
}| Topic | Description |
|---|---|
| Reflective API | Method naming conventions and executable attributes |
| Fluent API | Fluent Given/When/Then builder |
| Stories | Story metadata and grouping |
| Examples | Data-driven scenarios with ExampleTable |
| Reporters | Console, HTML, Markdown, Text, and Diagnostics reporters |
| Configuration | Customizing the BDDfy pipeline |
| Extensibility | Custom reporters, scanners, and step executors |
| Async Support | Async Task and async void steps |
| Tags | Tagging and filtering scenarios |