Package org.jbehave.core.story.domain

Source Code of org.jbehave.core.story.domain.MultiStepScenario

package org.jbehave.core.story.domain;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.jbehave.core.exception.VerificationException;
import org.jbehave.core.story.renderer.Renderer;


/**
* <p>A Scenario describes a series of events, run in a particular
* context, and for which certain outcomes are expected.</p>
*
* <p>This class allows a scenario to be implemented with
* instances of particular givens, events and outcomes.
* Each {@link Given}, {@link Event} or {@link Outcome} should be
* represented by a different class, which can be reused in different
* scenarios.</p>
*
* <p>A scenario's elements can be used to describe it thus:<ul>
* <li>Given <a context></li>
* <li>When <an event happens></li>
* <li>Then <an outcome should occur></li>.
* </ul></p>
*
* <p>eg:<ul>
* <li>Given that I already have two crosses in opposite corners</li>
* <li>When I put a cross in the middle</li>
* <li>Then I should win the game.</li>
* </ul></p>
*
* <p>Sometimes a scenario may only finish after several events and
* the outcomes that result from them. Also, you may want to carry out
* checks on the way through using Outcomes that are not related to
* the outcome of the scenario. For instance, you may login to a web app
* and then ensure you are at the "welcome" page before continuing with
* the scenario. Each Given, Event and Outcome is considered a {@link Step},
* and Steps can be chained together in any arbitrary sequence to accomplish
* this.</p>
*
* <p>Each scenario runs as follows:<ul>
* <li>Assemble the steps (Givens, Events and Outcomes)</li>
* <li>Perform each step</li>
* <li>In reverse order, tidy up each step</li>
* </ul>
*
* <p>The annotation methods {@link #given(Given)}, {@link #when(Event)} and
* {@link #then(Outcome)} are used to make the Scenario code easier to read.</p>
*
* <p>ScenarioUsingSteps also gives you easy access to JBehave's MiniMock
* framework. This allows you to mock out the bits of the system that you
* haven't written yet. The Scenario will report the use of mocks, but
* will not consider them a failure.</p>
*
* @author <a href="mailto:dan.north@thoughtworks.com">Dan North</a>
* @author <a href="mailto:liz@thoughtworks.com">Elizabeth Keogh</a>
*/
public abstract class MultiStepScenario implements Scenario {
   
    private static final String UNSPECIFIED = "Unspecified";
    private static final String SPECIFIED = "Specified";
    private static final String RUN = "Run";
    private static final String CLEANED = "Cleaned";
   
    private List steps = new ArrayList();
    private String state;

    public MultiStepScenario() {
        state = UNSPECIFIED;
    }

    public final void specify() {
        checkState(UNSPECIFIED);
        specifySteps();
        state = SPECIFIED;
    }

    protected abstract void specifySteps();

    public void run(World world) {
        checkState(SPECIFIED);
        try {
            for (Iterator i = steps.iterator(); i.hasNext();) {
                Step step = (Step) i.next();
                step.perform(world);
            }
        } catch (VerificationException e) {
            throw e;
        } catch (Exception e) {
            throw new VerificationException("Exception in Scenario", e);
        } finally {
            state = RUN;
        }
    }

    private void checkState(String expected) {
        if (state != expected) { throw new IllegalStateException("Current state is " + state + ", should be " + expected); }
    }

    public void cleanUp(World world) {
        if (shouldCleanUp()) {
            for (ListIterator i = steps.listIterator(steps.size()); i.hasPrevious();) {
                ((AbstractStep) i.previous()).cleanUp(world);
            }
        }
        state = CLEANED;
    }

    protected boolean shouldCleanUp() {
        return state == RUN;
    }

    public void narrateTo(Renderer renderer) {
        checkState(SPECIFIED);
        renderer.renderScenario(this);
        for (Iterator i = steps.iterator(); i.hasNext();) {
            ((Step)i.next()).narrateTo(renderer);
        }
    }

    public boolean containsMocks() {
        for (Iterator i = steps.iterator(); i.hasNext();) {
            Step step = (Step) i.next();
            if (step.containsMocks()) {
                return true;
            }
        }
        return false;
    }
   
    public void verifyMocks() {
       
    }
   
    protected void given(Given given) {
        steps.add(new GivenStep(given));
    }
   
    protected void given(Scenario scenario) {
        scenario.specify();
        steps.add(new GivenStep(new GivenScenario(scenario)));
    }

    protected void when(Event event) {
        steps.add(new EventStep(event));
    }
   
    protected void then(final Outcome outcome) {
        steps.add(new OutcomeStep(outcome));
        if (outcome instanceof OutcomeWithExpectations) {
            injectAfterGivens(new AbstractStep(outcome) {
                public void perform(World world) {
                    ((OutcomeWithExpectations)outcome).setExpectationsIn(world);
                }
            }
            );
        }
    }

    private void injectAfterGivens(Step step) {
        ListIterator i = steps.listIterator(steps.size());
        while (i.hasPrevious()) {
            Object maybeGivenStep = i.previous();
            if (maybeGivenStep instanceof GivenStep) {
                steps.add(i.nextIndex() + 1, step);
                return;
            }
        }
        // if we get here, there weren't any givens
        steps.add(0, step);
    }
}
TOP

Related Classes of org.jbehave.core.story.domain.MultiStepScenario

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.