Step filters

Adam Ralph edited this page Feb 23, 2018 · 7 revisions
Clone this wiki locally

When running a scenario, xBehave.net gathers the definitions of the steps which constitute that 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> steps)
    {
        ...
    }
}

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 and xBehave.net will then run whatever sequence of steps are returned at the end of this pipeline. You may declare your attributes at the assembly, type or method level and 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:

private sealed class ContinueAfterThenAttribute
    : Attribute, IFilter<IStepDefinition>
{
    public IEnumerable<IStepDefinition> Filter(IEnumerable<IStepDefinition> steps)
    {
        var then = false;
        return steps.Select(step => step.OnFailure(
            then || (then = step.Text.StartsWith(
                    "Then ", StringComparison.OrdinalIgnoreCase))
            ? RemainingSteps.Run
            : RemainingSteps.Skip));
    }
}

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 ".