Configuring Scenarios

In JBehave, there is a separation of concerns between Scenario and Steps classes:

Even if each executable Scenario Java class can be configured independently, it is good pratice to collect the configuration that applies to all Scenarios in an abstract (i.e. not executable) base class:

public abstract class TraderScenario extends JUnitScenario {

    // Define how to resolve textual story or scenarios file based on the Java class
    private static ScenarioNameResolver resolver = new UnderscoredCamelCaseResolver(".story");

    public TraderScenario(final Class scenarioClass) {
        super(new PropertyBasedConfiguration() {
            @Override
            public ScenarioDefiner forDefiningScenarios() {
                return new ClasspathScenarioDefiner(resolver, new PatternScenarioParser(keywords()));
            }

            // Define the scenario reporters
            @Override
            public ScenarioReporter forReportingScenarios() {
                return new ScenarioReporterBuilder(new FilePrintStreamFactory(scenarioClass, resolver))
                            .with(CONSOLE)
                            .with(TXT)
                            .with(HTML)
                            .with(XML)
                            .build();
            }

        });

        // Define the Steps configuration
        StepsConfiguration configuration = new StepsConfiguration();
        configuration.useMonitor(new SilentStepMonitor()); // use new PrintStreamStepMonitor() to debug step matching issues
        configuration.useKeyWords(new I18nKeyWords(Locale.ENGLISH)); // use different Locale for different languages
        configuration.usePatternBuilder(new PrefixCapturingPatternBuilder("$")); // could use different char (e.g. '%') to identify parameters in annotation patterns
		configuration.useParameterConverters(new ParameterConverters(
        		monitor, new DateConverter(new SimpleDateFormat("dd/MM/yyyy"))));  // defines custom converter for Date objects with format dd/MM/yyyy
        
        // Define the Steps used by the Scenario class        
        addSteps(createSteps(configuration));
    }

    // Here we are instantiating Steps as POJOs
    protected CandidateSteps[] createSteps(StepsConfiguration configuration) {
        return new StepsFactory(configuration).createCandidateSteps(new TraderSteps(new TradingService()), new BeforeAfterSteps());
    }

If we wanted to use an inversion of control container to compose our Steps with all its dependencies, all we'd need to do is to override the createSteps method using a different StepsFactory and use that as your base Scenario class. For example, to use with a Spring container:

public abstract class SpringTraderScenario extends TraderScenario {

    public SpringTraderScenario(Class scenarioClass) {
        super(scenarioClass);
    }

    @Override
    protected CandidateSteps[] createSteps(StepsConfiguration configuration) {
        ListableBeanFactory parent = new SpringApplicationContextFactory("org/jbehave/examples/trader/spring/steps.xml")
                                    .getApplicationContext();
        return new SpringStepsFactory(configuration, parent).createCandidateSteps();
    }

}

Once we have a base Scenario class, all we need to do is to extend it providing the name of the executable Scenario class that maps to the textual scenario file. For example, to map to trader_is_alerted_of_status.story using the resolver defined above:

public class TraderIsAlertedOfStatus extends TraderScenario {

    public TraderIsAlertedOfStatus() {
        super(TraderIsAlertedOfStatus.class);
    }

}
Note that JBehave follow the configuration-by-convention approach, by which a default value of the configuration element is provided and can be overridden, if so desidered.

Scenario Configuration Elements

While Scenarios are designed to be highly configurable, they come with a default behaviour for the most useful configuration. Configuration is the main interface for configuring all the components of a scenario.

The configurable elements of the scenario include:

StepCreator: Represents the strategy for the creation of executable steps from a given scenario definition matching a list of candidate steps. The default implementation is UnmatchedToPendingStepCreator.

ScenarioDefiner: Loads scenarios contained in a story from a given scenario class. The default implementation is ClasspathScenarioDefiner.

ScenarioReporter: Allows the runner to report the state of running scenarios. The default implementation is PrintStreamScenarioReporter.

ErrorStrategy: Allows to define the strategy for error handling. The default value is RETHROW.

KeyWords: Allows to specify the keywords used. The default value is I18nKeyWords.

JBehave provides two useful base implementations that users can extend to override only the elements that differ from default behaviour:

MostUsefulConfiguration: provides default configuration that most user will find appropriate

PropertyBasedConfiguration: overrides default configuration via system properties

Steps Configuration Elements

Steps can also be configured to a high degree via the StepsConfiguration. Among the elements that can be configured are:

StepPatternBuilder: defaults to PrefixCapturingPatternBuilder.

StepMonitor: defaults to SilentStepMonitor, useful to either debug the step matching or to describe the steps being performed to some output.

ParameterConverters: facade for collecting user-defined ParameterConverters.

KeyWords: defaults to I18nKeyWords.