- Revision
- 616
- Author
- tastapod
- Date
- 2006-12-06 03:31:07 -0600 (Wed, 06 Dec 2006)
Log Message
[dn] Added Story.specify() for parity with Scenario.specify(). Replaced Story.run(World) with Story.run() - stories are responsible for creating their own world. ScenarioDrivenStory uses a HashMapWorld by default but this can be overridden by subclasses. Fixed up Mauro's StoryBuilder - I think.
Modified Paths
- trunk/core/src/behaviour/jbehave/core/story/SimpleStory.java
- trunk/core/src/behaviour/jbehave/core/story/StoryRunnerBehaviour.java
- trunk/core/src/behaviour/jbehave/core/story/domain/NarrativeBehaviour.java
- trunk/core/src/behaviour/jbehave/core/story/domain/ScenarioDrivenStoryBehaviour.java
- trunk/core/src/behaviour/jbehave/core/story/renderer/PlainTextRendererBehaviour.java
- trunk/core/src/java/jbehave/core/story/StoryBuilder.java
- trunk/core/src/java/jbehave/core/story/StoryRunner.java
- trunk/core/src/java/jbehave/core/story/domain/ScenarioDrivenStory.java
- trunk/core/src/java/jbehave/core/story/domain/Story.java
- trunk/examples/atm/src/stories/example/atm/stories/UserWithdrawsCash.java
- trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/HellboundStory.java
- trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/ThePlayerDropsTheGlyph.java
- trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/ThePlayerInteractsWithTheGlyph.java
Diff
Modified: trunk/core/src/behaviour/jbehave/core/story/SimpleStory.java (615 => 616)
--- trunk/core/src/behaviour/jbehave/core/story/SimpleStory.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/behaviour/jbehave/core/story/SimpleStory.java 2006-12-06 09:31:07 UTC (rev 616) @@ -22,6 +22,9 @@ public SimpleStory() { super(new Narrative(ROLE, FEATURE, BENEFIT)); + } + + public void specify() { addScenario(new PlainTextRendererWorks()); addScenario(new PlainTextRendererStillWorks()); }
Modified: trunk/core/src/behaviour/jbehave/core/story/StoryRunnerBehaviour.java (615 => 616)
--- trunk/core/src/behaviour/jbehave/core/story/StoryRunnerBehaviour.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/behaviour/jbehave/core/story/StoryRunnerBehaviour.java 2006-12-06 09:31:07 UTC (rev 616) @@ -38,15 +38,15 @@ mock = mock(Story.class); mock.expects("addListener").with(isA(PlainTextScenarioListener.class)); - mock.expects("run").with(isA(World.class)).will(returnValue(new ScenarioResult[] {resultA, resultB})); + mock.expects("run").with(a(World.class)).will(returnValue(new ScenarioResult[] {resultA, resultB})); } public Narrative narrative() { return ((Story)mock).narrative(); } - public void run(World world) { - ((Story)mock).run(world); + public void run() { + ((Story)mock).run(); } public void addListener(BehaviourListener listener) { @@ -57,5 +57,7 @@ throw new UnsupportedOperationException("Should not be called"); } + public void specify() { + } } }
Modified: trunk/core/src/behaviour/jbehave/core/story/domain/NarrativeBehaviour.java (615 => 616)
--- trunk/core/src/behaviour/jbehave/core/story/domain/NarrativeBehaviour.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/behaviour/jbehave/core/story/domain/NarrativeBehaviour.java 2006-12-06 09:31:07 UTC (rev 616) @@ -24,7 +24,7 @@ Mock renderer = mock(Renderer.class); // expect... - renderer.expects("renderNarrative").with(sameInstanceAs(narrative)); + renderer.expects("renderNarrative").with(narrative); // when... narrative.narrateTo((Renderer)renderer);
Modified: trunk/core/src/behaviour/jbehave/core/story/domain/ScenarioDrivenStoryBehaviour.java (615 => 616)
--- trunk/core/src/behaviour/jbehave/core/story/domain/ScenarioDrivenStoryBehaviour.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/behaviour/jbehave/core/story/domain/ScenarioDrivenStoryBehaviour.java 2006-12-06 09:31:07 UTC (rev 616) @@ -23,12 +23,16 @@ */ public class ScenarioDrivenStoryBehaviour extends UsingMiniMock { public void shouldRunScenariosInOrder() throws Exception { - World world = (World)stub(World.class); + final World world = (World)stub(World.class); // given... Narrative narrative = new Narrative("","",""); AScenario scenarioA = new AScenario(); AScenario scenarioB = new AScenario(); - AStory story = new AStory(narrative); + AStory story = new AStory(narrative) { + protected World createWorld() { + return world; + } + }; story.addScenario((Scenario) scenarioA); story.addScenario((Scenario) scenarioB); @@ -36,16 +40,20 @@ scenarioB.expects("run").with(world); // when... - story.run(world); + story.run(); // then... verifyMocks(); } public void shouldInformListenersOfScenarioResult() { - World world = (World)stub(World.class); + final World world = (World)stub(World.class); Narrative narrative = new Narrative("","",""); - AStory story = new AStory(narrative); + AStory story = new AStory(narrative) { + protected World createWorld() { + return world; + } + }; Mock listener = mock(BehaviourListener.class); AScenario scenario = new AScenario(); @@ -57,15 +65,19 @@ story.addScenario((Scenario)scenario); story.addListener((BehaviourListener)listener); - story.run(world); + story.run(); verifyMocks(); } public void shouldInformListenersOfScenarioUsingMocks() { - World world = (World) stub(World.class); + final World world = (World) stub(World.class); Narrative narrative = new Narrative("","",""); - AStory story = new AStory(narrative); + AStory story = new AStory(narrative) { + protected World createWorld() { + return world; + } + }; Mock listener = mock(BehaviourListener.class); AScenario scenario = new AScenario(); @@ -78,15 +90,19 @@ story.addScenario((Scenario)scenario); story.addListener((BehaviourListener)listener); - story.run(world); + story.run(); verifyMocks(); } public void shouldInformListenersOfScenarioFailure() { - World world = (World) stub(World.class); + final World world = (World) stub(World.class); Narrative narrative = new Narrative("","",""); - AStory story = new AStory(narrative); + AStory story = new AStory(narrative) { + protected World createWorld() { + return world; + } + }; Mock listener = mock(BehaviourListener.class); AScenario scenario = new AScenario(); @@ -98,15 +114,19 @@ story.addScenario((Scenario)scenario); story.addListener((BehaviourListener)listener); - story.run(world); + story.run(); verifyMocks(); } public void shouldCleanUpScenariosEvenIfVerificationFails() { - World world = (World) stub(World.class); + final World world = (World) stub(World.class); Narrative narrative = new Narrative("","",""); - AStory story = new AStory(narrative); + AStory story = new AStory(narrative) { + protected World createWorld() { + return world; + } + }; Mock listener = mock(BehaviourListener.class); AScenario scenario = new AScenario(); @@ -118,7 +138,7 @@ story.addScenario((Scenario)scenario); try { - story.run(world); + story.run(); } catch (VerificationException e) { // Expected, but AFTER cleanUp. } @@ -132,6 +152,8 @@ public AStory(Narrative narrative) { super(narrative); } + public void specify() { + } } private class AScenario implements Scenario {
Modified: trunk/core/src/behaviour/jbehave/core/story/renderer/PlainTextRendererBehaviour.java (615 => 616)
--- trunk/core/src/behaviour/jbehave/core/story/renderer/PlainTextRendererBehaviour.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/behaviour/jbehave/core/story/renderer/PlainTextRendererBehaviour.java 2006-12-06 09:31:07 UTC (rev 616) @@ -29,6 +29,7 @@ PlainTextRenderer renderer = new PlainTextRenderer(printStream); ScenarioDrivenStory story = new SimpleStory(); + story.specify(); story.narrateTo(renderer); String result = byteStream.toString();
Modified: trunk/core/src/java/jbehave/core/story/StoryBuilder.java (615 => 616)
--- trunk/core/src/java/jbehave/core/story/StoryBuilder.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/java/jbehave/core/story/StoryBuilder.java 2006-12-06 09:31:07 UTC (rev 616) @@ -3,10 +3,14 @@ import java.text.MessageFormat; import java.util.Iterator; +import jbehave.core.story.codegen.domain.BasicDetails; import jbehave.core.story.codegen.domain.ScenarioDetails; import jbehave.core.story.codegen.domain.StoryDetails; +import jbehave.core.story.domain.Event; +import jbehave.core.story.domain.Given; import jbehave.core.story.domain.MultiStepScenario; import jbehave.core.story.domain.Narrative; +import jbehave.core.story.domain.Outcome; import jbehave.core.story.domain.Scenario; import jbehave.core.story.domain.ScenarioDrivenStory; import jbehave.core.story.domain.Story; @@ -21,65 +25,83 @@ public class StoryBuilder { private StoryDetails details; + private final String rootPackageName; private ClassLoader classLoader; + private final ClassBuilder builder = new ClassBuilder(); public StoryBuilder(StoryDetails details, String rootPackageName) { this(details, rootPackageName, Thread.currentThread().getContextClassLoader()); } - public StoryBuilder(StoryDetails details, String rootPackageName, ClassLoader classLaoder) { + public StoryBuilder(StoryDetails details, String rootPackageName, ClassLoader classLoader) { this.details = details; - this.classLoader = classLaoder; - } + this.rootPackageName = rootPackageName; + this.classLoader = classLoader; + } public Story story(){ - ScenarioDrivenStory story = new ScenarioDrivenStory(new Narrative(details.role, details.feature, details.benefit)); - for ( Iterator i = details.scenarios.iterator(); i.hasNext(); ){ - story.addScenario(scenario((ScenarioDetails)i.next(), details.name)); - } + ScenarioDrivenStory story = new ScenarioDrivenStory(new Narrative(details.role, details.feature, details.benefit)) { + public void specify() { + for ( Iterator i = details.scenarios.iterator(); i.hasNext(); ){ + addScenario(scenario((ScenarioDetails)i.next(), details.name)); + } + } + }; return story; } private Scenario scenario(final ScenarioDetails details, String storyName) { return new MultiStepScenario() { public void specify() { - // TODO fix ScenarioDetails to have arbitrary steps + // given + for (Iterator i = details.context.givens.iterator(); i.hasNext();) { + BasicDetails given = (BasicDetails)i.next(); + given((Given)builder.newGiven(given.name)); + } + + // when + when((Event)builder.newEvent(details.event.name)); + + // then + for (Iterator i = details.outcome.outcomes.iterator(); i.hasNext();) { + BasicDetails outcome = (BasicDetails)i.next(); + then((Outcome)builder.newOutcome(outcome.name)); + } } }; } - private Object newInstance(String name) { - try { - return classLoader.loadClass(name).newInstance(); - } catch ( Exception e) { - throw new RuntimeException("Failed to create instance for name "+name, e); - } - } - - private static final class ClassNameBuilder { + private final class ClassBuilder { private static final String CLASS_NAME_TEMPLATE = "{0}.{1}.{2}"; private static final String GIVENS = "givens"; private static final String EVENTS = "events"; private static final String OUTCOMES = "outcomes"; - private final String root; - public ClassNameBuilder(final String root) { - this.root = root; + public Object newGiven(String name) { + return newInstance(name, GIVENS); } - - public String givenName(String name){ - return MessageFormat.format(CLASS_NAME_TEMPLATE, new Object[]{root, GIVENS, toCamelCase(name)}); + public Object newEvent(String name) { + return newInstance(name, EVENTS); } - - public String eventName(String name){ - return MessageFormat.format(CLASS_NAME_TEMPLATE, new Object[]{root, EVENTS, toCamelCase(name)}); + public Object newOutcome(String name) { + return newInstance(name, OUTCOMES); } - public String outcomeName(String name){ - return MessageFormat.format(CLASS_NAME_TEMPLATE, new Object[]{root, OUTCOMES, toCamelCase(name)}); - } - + private String toCamelCase(String name) { return new CamelCaseConverter(name).toCamelCase(); } + + private Object newInstance(String name, String packageName) { + try { + String fullName = buildFullClassName(name, packageName); + return classLoader.loadClass(name).newInstance(); + } catch ( Exception e) { + throw new RuntimeException("Failed to create instance for name "+name, e); + } + } + + private String buildFullClassName(String name, String packageName) { + return MessageFormat.format(CLASS_NAME_TEMPLATE, new Object[]{rootPackageName, packageName, toCamelCase(name)}); + } } }
Modified: trunk/core/src/java/jbehave/core/story/StoryRunner.java (615 => 616)
--- trunk/core/src/java/jbehave/core/story/StoryRunner.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/java/jbehave/core/story/StoryRunner.java 2006-12-06 09:31:07 UTC (rev 616) @@ -35,6 +35,7 @@ public void run(String storyClassName, PrintStream printStream) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Story story = loadStory(storyClassName, classLoader); + story.specify(); run(story, printStream); } @@ -43,10 +44,9 @@ } public void run(Story story, PrintStream printStream) { - World world = new HashMapWorld(); PlainTextScenarioListener listener = new PlainTextScenarioListener(new OutputStreamWriter(printStream)); story.addListener(listener); - story.run(world); + story.run(); listener.printReport(); }
Modified: trunk/core/src/java/jbehave/core/story/domain/ScenarioDrivenStory.java (615 => 616)
--- trunk/core/src/java/jbehave/core/story/domain/ScenarioDrivenStory.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/java/jbehave/core/story/domain/ScenarioDrivenStory.java 2006-12-06 09:31:07 UTC (rev 616) @@ -33,7 +33,7 @@ * @author <a href="" PROTECTED]">Dan North</a> * @author <a href="" PROTECTED]">Elizabeth Keogh</a> */ -public class ScenarioDrivenStory implements Story { +public abstract class ScenarioDrivenStory implements Story { private final Narrative narrative; private final List scenarios; private final List listeners; @@ -56,14 +56,25 @@ public Narrative narrative() { return narrative; } - - public void run(World world) { + + public void run() { for (Iterator i = scenarios.iterator(); i.hasNext();) { Scenario scenario = (Scenario) i.next(); - informListeners(runScenario(world, this.getClass(), scenario)); + informListeners(runScenario(createWorld(), this.getClass(), scenario)); } } - + + /** + * Creates a new world to be passed into each scenario + * + * The default is a [EMAIL PROTECTED] HashMapWorld}. Override this to supply your own world + * + * @return a new world + */ + protected World createWorld() { + return new HashMapWorld(); + } + private ScenarioResult runScenario(World world, Class storyClass, Scenario scenario) { ScenarioResult result; String storyDescription = new CamelCaseConverter(storyClass).toPhrase();
Modified: trunk/core/src/java/jbehave/core/story/domain/Story.java (615 => 616)
--- trunk/core/src/java/jbehave/core/story/domain/Story.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/core/src/java/jbehave/core/story/domain/Story.java 2006-12-06 09:31:07 UTC (rev 616) @@ -21,8 +21,10 @@ public interface Story extends Renderable { Narrative narrative(); + + void specify(); - void run(World world); + void run(); void addListener(BehaviourListener listener);
Modified: trunk/examples/atm/src/stories/example/atm/stories/UserWithdrawsCash.java (615 => 616)
--- trunk/examples/atm/src/stories/example/atm/stories/UserWithdrawsCash.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/examples/atm/src/stories/example/atm/stories/UserWithdrawsCash.java 2006-12-06 09:31:07 UTC (rev 616) @@ -26,13 +26,12 @@ "to be able to withdraw cash from an ATM", "I don't have to visit the bank" )); + } + public void specify() { addScenario(new HappyScenario()); - addScenario(new HappyScenarioWithOverdraft()); - addScenario(new OverdrawnWithoutPermission()); - addScenario(new InLotsOfTrouble()); } }
Modified: trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/HellboundStory.java (615 => 616)
--- trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/HellboundStory.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/HellboundStory.java 2006-12-06 09:31:07 UTC (rev 616) @@ -9,4 +9,7 @@ super(narrative); } + public void specify() { + // TODO Auto-generated method stub + } }
Modified: trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/ThePlayerDropsTheGlyph.java (615 => 616)
--- trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/ThePlayerDropsTheGlyph.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/ThePlayerDropsTheGlyph.java 2006-12-06 09:31:07 UTC (rev 616) @@ -10,9 +10,10 @@ public ThePlayerDropsTheGlyph() { super(new Narrative("game player", "to drop the glyph", " I can save time")); - - addScenario(new ThePlayerDropsTheGlyphIntoAnEmptyPit()); - addScenario(new ThePlayerDropsTheGlyphOntoJunk()); } + public void specify() { + addScenario(new ThePlayerDropsTheGlyphIntoAnEmptyPit()); + addScenario(new ThePlayerDropsTheGlyphOntoJunk()); + } }
Modified: trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/ThePlayerInteractsWithTheGlyph.java (615 => 616)
--- trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/ThePlayerInteractsWithTheGlyph.java 2006-12-05 19:36:06 UTC (rev 615) +++ trunk/examples/hellbound/src/stories/com/sirenian/hellbound/stories/ThePlayerInteractsWithTheGlyph.java 2006-12-06 09:31:07 UTC (rev 616) @@ -11,7 +11,9 @@ public ThePlayerInteractsWithTheGlyph() { super(new Narrative("game player", "to move the shape", "I can make space for the next glyph")); - + } + + public void specify() { addScenario(new ThePlayerMovesTheGlyph()); addScenario(new ThePlayerRotatesTheGlyphLeft()); addScenario(new ThePlayerRotatesTheGlyphRight());
To unsubscribe from this list please visit:
