AnnotatedPathRunner.java

  1. package org.jbehave.core.junit;

  2. import java.util.List;

  3. import org.jbehave.core.annotations.UsingPaths;
  4. import org.jbehave.core.configuration.AnnotationBuilder;
  5. import org.jbehave.core.embedder.DelegatingEmbedderMonitor;
  6. import org.jbehave.core.embedder.Embedder;
  7. import org.jbehave.core.embedder.EmbedderMonitor;
  8. import org.jbehave.core.io.StoryNameResolver;
  9. import org.jbehave.core.io.UnderscoredToCapitalized;
  10. import org.junit.runner.Description;
  11. import org.junit.runner.Runner;
  12. import org.junit.runner.notification.Failure;
  13. import org.junit.runner.notification.RunNotifier;
  14. import org.junit.runners.model.InitializationError;

  15. /**
  16.  * A JUnit {@link Runner} that uses a {@link UsingPaths} annotation to specify
  17.  * which story paths to run and uses the {@link RunNotifier} to provide a
  18.  * {@link Description} for each. The story description uses a
  19.  * {@link StoryNameResolver} (overridable via the {@link #storyNameResolver()}
  20.  * method) to resolve the story path to a name.
  21.  */
  22. public class AnnotatedPathRunner extends AnnotatedEmbedderRunner {

  23.     private final AnnotationBuilder annotationBuilder;
  24.     private final StoryNameResolver nameResolver;
  25.     private final List<String> paths;

  26.     /**
  27.      * Class constructor.
  28.      *
  29.      * @param annotatedClass the annotated {@link Class}.
  30.      * @throws InitializationError if an error occurs.
  31.      */
  32.     public AnnotatedPathRunner(Class<?> annotatedClass) throws InitializationError {
  33.         super(annotatedClass);
  34.         this.annotationBuilder = annotationBuilder();
  35.         this.nameResolver = storyNameResolver();
  36.         this.paths = annotationBuilder.findPaths();
  37.     }

  38.     protected StoryNameResolver storyNameResolver() {
  39.         return new UnderscoredToCapitalized();
  40.     }

  41.     @Override
  42.     public Description getDescription() {
  43.         Description description = Description.createSuiteDescription(testClass());
  44.         for (String path : paths) {
  45.             description.addChild(createDescriptionForPath(path));
  46.         }

  47.         return description;
  48.     }

  49.     private Description createDescriptionForPath(String path) {
  50.         String name = nameResolver.resolveName(path);
  51.         return Description.createTestDescription(testClass(), name);
  52.     }

  53.     @Override
  54.     protected void collectInitializationErrors(List<Throwable> errors) {
  55.         // overridden to avoid JUnit-specific errors
  56.     }

  57.     @Override
  58.     protected void validateInstanceMethods(List<Throwable> errors) {
  59.         // overridden to avoid JUnit-specific errors
  60.     }

  61.     @Override
  62.     public void run(RunNotifier notifier) {
  63.         Embedder embedder = annotationBuilder.buildEmbedder();
  64.         NotifierEmbedderMonitor notifierEmbedderMonitor = new NotifierEmbedderMonitor(embedder.embedderMonitor(),
  65.                 notifier);
  66.         embedder.useEmbedderMonitor(notifierEmbedderMonitor);

  67.         try {
  68.             embedder.runStoriesAsPaths(paths);
  69.         } finally {
  70.             notifierEmbedderMonitor.storyFinished();
  71.         }
  72.     }

  73.     /**
  74.      * {@link EmbedderMonitor} that reports story updates to a
  75.      * {@link RunNotifier}.
  76.      */
  77.     private final class NotifierEmbedderMonitor extends DelegatingEmbedderMonitor {
  78.         private final RunNotifier notifier;
  79.         private Description currentStory;

  80.         /**
  81.          * Creates a NotifierEmbedderMonitor
  82.          *
  83.          * @param delegate the EmbedderMonitor delegate
  84.          * @param notifier the RunNotifier
  85.          */
  86.         private NotifierEmbedderMonitor(EmbedderMonitor delegate, RunNotifier notifier) {
  87.             super(delegate);
  88.             this.notifier = notifier;
  89.         }

  90.         @Override
  91.         public void runningStory(String path) {
  92.             super.runningStory(path);
  93.             storyFinished();
  94.             currentStory = createDescriptionForPath(path);
  95.             notifier.fireTestStarted(currentStory);
  96.         }

  97.         @Override
  98.         public void storyFailed(String path, Throwable cause) {
  99.             super.storyFailed(path, cause);
  100.             notifier.fireTestFailure(new Failure(currentStory, cause));
  101.             notifier.fireTestFinished(currentStory);
  102.             currentStory = null;
  103.         }

  104.         /**
  105.          * Finishes the last story.
  106.          */
  107.         private void storyFinished() {
  108.             if (currentStory == null) {
  109.                 return;
  110.             }
  111.             notifier.fireTestFinished(currentStory);
  112.         }
  113.     }
  114. }