Skip to content

Composite Steps Definition (v2.x)

Suremaker edited this page Jan 13, 2019 · 1 revision

Page version: 3.x / 2.x

Since version 2.2.0 it is possible to define composite steps that are made of other steps.

The composite steps may be found useful in complex, long running scenarios (like end-to-end tests) where scenario high-level steps are composed of set of sub-steps. Normally, such complex steps explicitly call a set of methods (usually other existing steps) to perform actions. The composite step gives the same behaviour but with higher granularity and detail, as all of sub-steps used in composition would be included in progress notification and reports.

When composite step is executed, all sub-steps are executed in declaration order making parent step passing if all are successful. The sub-steps will be included in progress notification as well as in final execution reports, where step number will consist of step number in composite step prefixed by parent step number. It is possible to make multiple level composite steps i.e. use composite step as a sub-step of higher level composite step.

Composite step definition

To define a composite step, the step method has to return either CompositeStep or Task<CompositeStep> type.
The CompositeStep return value should be created in following way: CompositeStep.DefineNew().AddSteps(...).Build()

Example definition:

private async Task<CompositeStep> Given_customer_is_logged_in()
{
    return CompositeStep
        .DefineNew()
        .AddSteps(
            Given_the_user_is_about_to_login,
            Given_the_user_entered_valid_login,
            Given_the_user_entered_valid_password,
            When_the_user_clicks_login_button,
            Then_the_login_operation_should_be_successful)
        .Build();
}

Please note that CompositeStep.DefineNew() returns a composite builder with fluent API interface, where:

  • Build() method should be called to return composite,
  • it is possible to add steps with basic and extended syntax with AddSteps() method,
  • it is possible to add asynchronous steps with basic and extended syntax with AddAsyncSteps() method (the method itself is synchronous),
  • it is possible to repeat AddSteps() / AddAsyncSteps() or even mix them,
  • it is possible to specify a context instance that would be shared between all sub-steps within the composite by using CompositeStep.DefineNew().WithContext() method.

To learn more about basic, extended and contextual steps, please read Scenario Steps Definition as the concept is identical.

Note: The CompositeStep.DefineNew()...Build() does not execute sub-steps but just creates a definition of the composite. The specified sub-steps are executed by the engine just after parent step method returns. It may sound a bit confusing but allows to predefine composite steps and reuse them in various steps as well as properly build a step hierarchy to render progress and report.

Using composite steps

Composite steps can be used to describe scenarios in the same way as regular steps:

  • the extended scenario syntax fully supports composite steps,
  • the basic scenario syntax supports composite steps only if RunScenarioAsync method is used due to fact that others will not accept non-void steps.

Example usage:

private async Task<CompositeStep> Given_customer_is_logged_in()
{
    return CompositeStep.DefineNew()
        .AddSteps(
            Given_the_user_is_about_to_login,
            Given_the_user_entered_valid_login,
            Given_the_user_entered_valid_password,
            When_the_user_clicks_login_button,
            Then_the_login_operation_should_be_successful)
        .Build();
}

[Scenario]
public async Task Ordering_products()
{
    await Runner.RunScenarioAsync(
        Given_customer_is_logged_in,
        When_customer_adds_products_to_basket,
        When_customer_pays_for_products_in_basket,
        Then_customer_should_receive_order_email);
}

Example output:

SCENARIO: Ordering products
  STEP 1/4: GIVEN customer is logged in...
  STEP 1.1/1.5: GIVEN the user is about to login...
  STEP 1.1/1.5: GIVEN the user is about to login (Passed after 1ms)
  STEP 1.2/1.5: AND the user entered valid login...
  STEP 1.2/1.5: AND the user entered valid login (Passed after <1ms)
  STEP 1.3/1.5: AND the user entered valid password...
  STEP 1.3/1.5: AND the user entered valid password (Passed after <1ms)
  STEP 1.4/1.5: WHEN the user clicks login button...
  STEP 1.4/1.5: WHEN the user clicks login button (Passed after 144ms)
  STEP 1.5/1.5: THEN the login operation should be successful...
  STEP 1.5/1.5: THEN the login operation should be successful (Passed after <1ms)
  STEP 1/4: GIVEN customer is logged in (Passed after 196ms)
  STEP 2/4: WHEN customer adds products to basket...

To see more examples of composite steps, please take a look at:

The example above shows various ways of defining composite (basic, extended, contextual, async) as well as shows that it is possible to mix them together.

Continue reading: DI Containers

Clone this wiki locally