Blog Post

Specflow - Advanced topics

Tuesday, October 4, 2016 9:12 AM

Scoped Bindings

Bindings (step definitions, hooks) are global for the entire SpecFlow project. This means that a step definition that is bound to a very generic step text, like When I save the changes becomes challenging to implement. The general solution for this problem is to phrase the scenarios in a way that the steps are phrased in a way that the usage context can be extracted from them (e.g. When I save the book details).

In some cases however, it is necessary to restrict the appliance of a step definition or hook based on certain conditions. This feature of SpecFlow can be used for this purpose.

Be careful! Coupling your step definitions to the features is an anti-pattern. Read more about it on the Cucumber Wiki

The scoped bindings can restrict the execution for

  • feature (by feature title)
  • scenario (by scenario title)
  • tag

The scope can be defined with the [Scope] attribute. (Prior to v1.8, scopes has to be specified with the [StepScope]attribute.)

[Scope(Tag = "mytag", Feature = "feature title", Scenario = "scenario title")] 

Hooks

The hooks (event bindings) can be used to perform additional automation logic on specific events, such as before executing a scenario.

Hooks are global, but can be restricted to run only for features or scenarios with a specific tag (see below). The execution order of hooks for the same event is undefined.

SUPPORTED HOOK ATTRIBUTES

Attribute Tag filtering Description

[BeforeTestRun] [AfterTestRun]

-

Automation logic that has to run before/after the entire test run
Note: As most of the unit test runners do not provide a hook for executing logic once the tests have been executed, the [AfterTestRun] event is triggered by the test assembly unload event. The exact timing and thread of this execution may therefore differ for each test runner.
The method it is applied to must be static.

[BeforeFeature] [AfterFeature]

+

Automation logic that has to run before/after executing each feature
The method it is applied to must be static.

[BeforeScenario] or [Before] [AfterScenario] or [After]

+

Automation logic that has to run before/after executing each scenario or scenario outline example
Short attribute names are available from v1.8.

[BeforeScenarioBlock] [AfterScenarioBlock]

+

Automation logic that has to run before/after executing each scenario block (e.g. between the "givens" and the "whens")

[BeforeStep] [AfterStep]

+

Automation logic that has to run before/after executing each scenario step

You can annotate a single method with multiple attributes.

HOOK EXECUTION ORDER

By default the hooks of the same type (e.g. two [BeforeScenario] hook) are executed in an unpredictable order. If you need to ensure a specific execution order, you can specify the Order property for the hook attributes.

[BeforeScenario(Order = 0)]
public void CleanDatabase()
{
    // we need to run this first
}

[BeforeScenario(Order = 100)]
public void LoginUser()
{
    // we can perform login based on a clean database
}

The value provided for the order attribute specifies the order, not the priority, ie. the hook with the lower number always executed earlier both for before and after hooks.

If no order is specified, the default order of 1000 is used. It is not recommended to depend on this default value though.

TAG SCOPING

Most of the hooks support tag scoping. This means that they are executed only if the feature or the scenario has at least one of the tags specified in the tag filter (tags are combined with OR). You can specify the tag in the attribute or usingScoped Bindings (from v1.8).

The following example starts Selenium for scenarios marked with the @web tag.

[BeforeScenario("web")]
public static void BeforeWebScenario()
{
    StartSelenium();
}

For the scenario, scenarioblock or step hooks, the following tags are considered:

  • tags defined for the feature
  • tags defined for the scenario
  • tags defined for the scenario outline
  • tags defined for the scenario outline example set (Examples:)

You can define more complex filters using the ScenarioContext class. The following example starts selenium if the scenario is tagged with @web and @automated.

[BeforeScenario("web")]
public static void BeforeWebScenario()
{
    if(ScenarioContext.Current.ScenarioInfo.Tags.Contains("automated"))
        StartSelenium();
}