AnnotatedPathRunner.java
package org.jbehave.core.junit;
import java.util.List;
import org.jbehave.core.annotations.UsingPaths;
import org.jbehave.core.configuration.AnnotationBuilder;
import org.jbehave.core.embedder.DelegatingEmbedderMonitor;
import org.jbehave.core.embedder.Embedder;
import org.jbehave.core.embedder.EmbedderMonitor;
import org.jbehave.core.io.StoryNameResolver;
import org.jbehave.core.io.UnderscoredToCapitalized;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.InitializationError;
/**
* A JUnit {@link Runner} that uses a {@link UsingPaths} annotation to specify
* which story paths to run and uses the {@link RunNotifier} to provide a
* {@link Description} for each. The story description uses a
* {@link StoryNameResolver} (overridable via the {@link #storyNameResolver()}
* method) to resolve the story path to a name.
*/
public class AnnotatedPathRunner extends AnnotatedEmbedderRunner {
private final AnnotationBuilder annotationBuilder;
private final StoryNameResolver nameResolver;
private final List<String> paths;
/**
* Class constructor.
*
* @param annotatedClass the annotated {@link Class}.
* @throws InitializationError if an error occurs.
*/
public AnnotatedPathRunner(Class<?> annotatedClass) throws InitializationError {
super(annotatedClass);
this.annotationBuilder = annotationBuilder();
this.nameResolver = storyNameResolver();
this.paths = annotationBuilder.findPaths();
}
protected StoryNameResolver storyNameResolver() {
return new UnderscoredToCapitalized();
}
@Override
public Description getDescription() {
Description description = Description.createSuiteDescription(testClass());
for (String path : paths) {
description.addChild(createDescriptionForPath(path));
}
return description;
}
private Description createDescriptionForPath(String path) {
String name = nameResolver.resolveName(path);
return Description.createTestDescription(testClass(), name);
}
@Override
protected void collectInitializationErrors(List<Throwable> errors) {
// overridden to avoid JUnit-specific errors
}
@Override
protected void validateInstanceMethods(List<Throwable> errors) {
// overridden to avoid JUnit-specific errors
}
@Override
public void run(RunNotifier notifier) {
Embedder embedder = annotationBuilder.buildEmbedder();
NotifierEmbedderMonitor notifierEmbedderMonitor = new NotifierEmbedderMonitor(embedder.embedderMonitor(),
notifier);
embedder.useEmbedderMonitor(notifierEmbedderMonitor);
try {
embedder.runStoriesAsPaths(paths);
} finally {
notifierEmbedderMonitor.storyFinished();
}
}
/**
* {@link EmbedderMonitor} that reports story updates to a
* {@link RunNotifier}.
*/
private final class NotifierEmbedderMonitor extends DelegatingEmbedderMonitor {
private final RunNotifier notifier;
private Description currentStory;
/**
* Creates a NotifierEmbedderMonitor
*
* @param delegate the EmbedderMonitor delegate
* @param notifier the RunNotifier
*/
private NotifierEmbedderMonitor(EmbedderMonitor delegate, RunNotifier notifier) {
super(delegate);
this.notifier = notifier;
}
@Override
public void runningStory(String path) {
super.runningStory(path);
storyFinished();
currentStory = createDescriptionForPath(path);
notifier.fireTestStarted(currentStory);
}
@Override
public void storyFailed(String path, Throwable cause) {
super.storyFailed(path, cause);
notifier.fireTestFailure(new Failure(currentStory, cause));
notifier.fireTestFinished(currentStory);
currentStory = null;
}
/**
* Finishes the last story.
*/
private void storyFinished() {
if (currentStory == null) {
return;
}
notifier.fireTestFinished(currentStory);
}
}
}