Step filters - adamralph/xbehave.net GitHub Wiki

When running a scenario, xBehave.net gathers the definitions of the steps in the scenario and runs them in sequence. To customise this sequence of steps, you have the ability to define custom step filter attributes.

public sealed class MyFilterAttribute : Attribute, IFilter<IStepDefinition>
{
    public IEnumerable<IStepDefinition> Filter(IEnumerable<IStepDefinition> source)
    {
        ...
    }
}

public class MyFeature
{
    [Scenario]
    [MyFilter]
    public void Scenario()
    {
        "Given something"
            .x(() => ...);

        "When something"
            .x(() => ...);

        "Then something"
            .x(() => ...);
    }
}

Before the steps are run, xBehave.net will identify all custom filter attributes which implement IFilter<IStepDefinition>. The sequence of steps will be passed through each filter in turn. xBehave.net will then run the sequence of steps returned at the end of this pipeline. You may declare your attributes at the assembly, type or method level. xBehave.net will find them and apply them in that order. If multiple filters are declared at any of those levels, xBehave.net will apply them in the order it finds them in the compiled assembly.

For example, you may want to define a filter which ensures that, after the first step beginning with "Then " has run, all subsequent steps are always run, regardless of whether a step fails:

public sealed class ContinueAfterThenAttribute
    : Attribute, IFilter<IStepDefinition>
{
    public IEnumerable<IStepDefinition> Filter(IEnumerable<IStepDefinition> source)
    {
        foreach (var step in source)
        {
            if (step.Text.StartsWith("Then ", StringComparison.OrdinalIgnoreCase))
            {
                step.OnFailure(RemainingSteps.Run);
            }

            yield return step;
        }
    }
}

public class ScenarioWithContinueAfterThen
{
    [Scenario]
    [ContinueAfterThen]
    public void Scenario()
    {
        "Given something"
            .x(() => { });

        "When something"
            .x(() => { });

        "Then something"
            .x(() => { throw new InvalidOperationException(); });

        "And something"
            .x(() => { });

        "And something else"
            .x(() => { });
    }
}

In this example, the steps "And something" and "And something else" will be run, even though the "Then something" steps fails, because they are after the first step beginning with "Then ".