Conditional Steps

The conditional steps mechanism allows the user to choose a step to execute based on the result of predicate evaluation. This mechanism can be used instead of conditional statements like if-else/switch in case of grow of number of steps with the same naming but different internal logic.

Let's consider the following switch operator with a bunch of conditions:

@Given("food for my pet")
public void prepareFoodForMyPet() {
    String partOfDay = ...;
    switch (partOfDay) {
        case "morning":
            // logic for morning
            break;
        case "evening":
            // logic for evening
            break;
        case "afternoon":
            // logic for evening
            break;
    }
}

With conditional steps the logic can be rewritten in the following way:

@Conditional(condition = PartOfDayCondition.class, value = "morning")
@Given("food for my pet")
public void prepareMorningFood() {
    // logic for morning
}
 
@Conditional(condition = PartOfDayCondition.class, value = "evening")
@Given("food for my pet")
public void prepareEveningFood() {
    // logic for evening
}
 
@Conditional(condition = PartOfDayCondition.class, value = "afternoon")
@Given("food for my pet")
public void prepareAfternoonFood() {
    // logic for afternoon
}

To make this work we need the following condition implementation:

public class PartOfDayCondition implements Predicate\<object\>
{
    @Override
    public boolean test(Object value)
    {
        String partOfDay = ...;
        return partOfDay.equals(value);
    }
}
</object\>

By default conditions are checked by DefaultStepConditionMatcher that requires conditions to have public non-args constructor, custom step condition matcher can be created by implementing the StepConditionMatcher interface and then registering the new implementation in a Configuration instance.

public class MyStepConditionMatcher implements StepConditionMatcher {
    @Override
    public boolean check(Class<? extends Predicate<Object>> type, Object value) {
        return ...;
    }
}
 
public class Stories extends JUnitStories {
 
    public Stories() {
        Configuration configuration = new MostUsefulConfiguration()
                .useStepConditionMatcher(new MyStepConditionMatcher())
                ...;
    }
}

Notes:

  • a condition at the method level has higher priority than a condition at the class level
  • if a step is annotated as conditional, then all the steps with the same wording must be conditional, otherwise, an exception is thrown
  • step is marked as pending if there are no steps matched condition or there is more than one matched step