Skip to main content

Context

Docs for xUnit SDK v0.4.0

Context objects carry metadata and extracted values through test execution. LiveDocContext is passed to step lambdas. FeatureContext, ScenarioContext, StepContext, SpecificationContext, and RuleContext provide typed access to the current test's title, description, tags, and values.

Given("a user with '100' credits", ctx =>
{
// Step-level context
var credits = ctx.Step!.Values[0].AsInt();
var stepTitle = ctx.Step!.Title;

// Feature-level context
var featureTitle = ctx.Feature?.Title;
var featureDesc = ctx.Feature?.Description;

// Scenario-level context
var scenarioName = ctx.Scenario?.Name;
});

Reference​

LiveDocContext​

The primary context object passed to step lambdas via the Action<LiveDocContext> and Func<LiveDocContext, Task> overloads.

public class LiveDocContext

Properties​

PropertyTypeDescription
FeatureFeatureContext?Feature metadata (BDD tests only).
SpecificationSpecificationContext?Specification metadata (MSpec tests only).
ScenarioScenarioContext?Current scenario metadata (BDD tests only).
RuleRuleContext?Current rule metadata (MSpec tests only).
StepStepContext?Current step metadata with extracted values.
Exampledynamic?Current example row data (outlines only).
TestCaseobject?Base test case context.
Null safety

Properties are nullable. In a [Scenario] method, Feature and Scenario are populated but Specification and Rule are null. In a [Rule] method, the reverse is true. Step is populated inside step lambdas.

StepContext​

Contains metadata about the currently executing step, including extracted values and parameters.

public class StepContext

Properties​

PropertyTypeDescription
TitlestringThe original step title as written in code.
DisplayTitlestringThe rendered title with placeholders replaced and quotes removed.
TypestringThe step keyword: "Given", "When", "Then", "And", or "But".
ValuesLiveDocValueArrayOrdered array of quoted values ('value').
ValuesRawstring[]Quoted values as raw strings.
ParamsLiveDocValueDictionaryNamed parameters (<name:value>).
ParamsRawIReadOnlyDictionary<string, string>Named parameters as raw strings.
Given("transferring '250.00' from <account:checking>", ctx =>
{
// Values: ordered quoted values
var amount = ctx.Step!.Values[0].AsDecimal(); // 250.00m

// Params: named parameters
var account = ctx.Step!.Params["account"].AsString(); // "checking"

// Metadata
var title = ctx.Step!.Title; // "transferring '250.00' from <account:checking>"
var display = ctx.Step!.DisplayTitle; // "transferring 250.00 from checking"
var type = ctx.Step!.Type; // "Given"
});

FeatureContext​

Metadata about the current BDD feature, populated from the [Feature] attribute.

public class FeatureContext

Properties​

PropertyTypeDescription
TitlestringThe feature title from [Feature("title")].
Descriptionstring?The description from Description = "...".
Tagsstring[]Tags associated with the feature.
[Feature("Shopping Cart", Description = "Gives cart-related steps a recognizable feature context.")]
public class CartTests : FeatureTest
{
public CartTests(ITestOutputHelper output) : base(output) { }

[Scenario]
public void Access_feature_context()
{
Given("context is available", ctx =>
{
Assert.Equal("Shopping Cart", ctx.Feature!.Title);
Assert.Equal("Gives cart-related steps a recognizable feature context.", ctx.Feature!.Description);
});
}
}

ScenarioContext​

Metadata about the current BDD scenario, populated from the [Scenario] or [ScenarioOutline] attribute.

public class ScenarioContext

Properties​

PropertyTypeDescription
NamestringThe scenario title/display name.
Descriptionstring?The scenario description.
Tagsstring[]Tags associated with the scenario.
StepsList<StepExecution>List of executed steps with results.
[Scenario("Login with valid credentials", Description = "Happy path")]
public void Login()
{
Given("a registered user", ctx =>
{
Assert.Equal("Login with valid credentials", ctx.Scenario!.Name);
Assert.Equal("Happy path", ctx.Scenario!.Description);
});
}

SpecificationContext​

Metadata about the current MSpec specification, populated from the [Specification] attribute.

public class SpecificationContext

Properties​

PropertyTypeDescription
TitlestringThe specification title.
Descriptionstring?The specification description.
Tagsstring[]Tags associated with the specification.

RuleContext​

Metadata and values for the currently executing MSpec rule. This is the primary API for value extraction in SpecificationTest.

public class RuleContext

Properties​

PropertyTypeDescription
NamestringThe rule title.
Descriptionstring?The rule description.
Tagsstring[]Tags associated with the rule.
ValuesLiveDocValueArrayOrdered array of quoted values from the rule title.
ValuesRawstring[]Quoted values as raw strings.
ParamsLiveDocValueDictionaryNamed parameters from the rule title.
ParamsRawIReadOnlyDictionary<string, string>Named parameters as raw strings.
[Specification("Calculator")]
public class CalcSpec : SpecificationTest
{
public CalcSpec(ITestOutputHelper output) : base(output) { }

[Rule("Multiplying '6' by '7' returns '42'")]
public void Multiplication()
{
var (a, b, expected) = Rule.Values.As<int, int, int>();
Assert.Equal(expected, a * b);

// Also available:
Assert.Equal("Multiplying '6' by '7' returns '42'", Rule.Name);
}
}

EnsureContext()​

// On FeatureTest
protected LiveDocContext EnsureContext()

// On SpecificationTest
protected LiveDocContext EnsureContext()

Returns the current LiveDocContext, initializing it if it hasn't been created yet. Normally the context is created automatically when the first step executes, but EnsureContext() can be called explicitly if you need context before any steps run.

[Scenario]
public void Verify_feature_metadata()
{
var ctx = EnsureContext();
Assert.Equal("Shopping Cart", ctx.Feature?.Title);
}

Context Flow​

BDD / FeatureTest​

[Feature] attribute
└── FeatureContext (title, description, tags)
│
[Scenario] / [ScenarioOutline] attribute
└── ScenarioContext (name, description, tags, steps)
│
Given/When/Then/And/But step method
└── StepContext (title, type, values, params)
│
LiveDocContext (aggregates all above)
└── Passed to: Action<LiveDocContext> lambda
[Feature("Checkout", Description = "Keeps payment details accessible to this checkout scenario.")]
public class CheckoutTests : FeatureTest
{
public CheckoutTests(ITestOutputHelper output) : base(output) { }

[Scenario("Process payment")]
public void Process_payment()
{
// ctx has: Feature, Scenario, Step
Given("a valid credit card with number '4111111111111111'", ctx =>
{
Assert.Equal("Checkout", ctx.Feature!.Title);
Assert.Equal("Process payment", ctx.Scenario!.Name);
Assert.Equal("Given", ctx.Step!.Type);
Assert.Equal("4111111111111111", ctx.Step!.Values[0].AsString());
});
}
}

MSpec / SpecificationTest​

[Specification] attribute
└── SpecificationContext (title, description, tags)
│
[Rule] / [RuleOutline] attribute
└── RuleContext (name, description, tags, values, params)
│
Rule property on SpecificationTest
└── Provides: Values, Params, ValuesRaw, ParamsRaw
[Specification("Math", Description = "Callers can rely on the arithmetic results covered by these rules.")]
public class MathSpec : SpecificationTest
{
public MathSpec(ITestOutputHelper output) : base(output) { }

[Rule("Adding '2' and '3' returns '5'")]
public void Addition()
{
// Specification context
Assert.Equal("Math", Specification.Title);
Assert.Equal("Callers can rely on the arithmetic results covered by these rules.", Specification.Description);

// Rule context with values
Assert.Equal("Adding '2' and '3' returns '5'", Rule.Name);
var (a, b, expected) = Rule.Values.As<int, int, int>();
Assert.Equal(expected, a + b);
}
}

ScenarioOutline / RuleOutline​

In outline methods, the Example dynamic property provides access to the current row's data:

[ScenarioOutline]
[Example("Alice", 25)]
public void Test(string name, int age)
{
Given("user <name> aged <age>", ctx =>
{
// Method parameters (typed)
Assert.Equal("Alice", name);
Assert.Equal(25, age);

// Dynamic Example property
Assert.Equal("Alice", (string)ctx.Example!.name);
Assert.Equal(25, (int)ctx.Example!.age);
});
}

Caveats​

  • ctx.Step is only populated inside step lambdas that use the Action<LiveDocContext> or Func<LiveDocContext, Task> overload. It is null if you use Action (no context).
  • Feature / Specification are mutually exclusive — one is always null depending on the base class.
  • Scenario / Rule are mutually exclusive — one is always null depending on the test attribute.
  • Example is null unless the test is a [ScenarioOutline] or [RuleOutline].
  • RuleContext on SpecificationTest provides Values and Params directly — you don't need a step lambda to access them.

See Also​