Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spring support #114

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 268 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,275 @@ been fixed already in the latest snapshot release.
And, *of course*, we'd also very much appreciate pull requests for fixes
that you have already made yourself. After all, this is where open source
shines most :)
## spring support
```
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.jbehave.core.ConfigurableEmbedder;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.embedder.Embedder;
import org.jbehave.core.embedder.EmbedderControls;
import org.jbehave.core.embedder.PerformableTree;
import org.jbehave.core.embedder.PerformableTree.RunContext;
import org.jbehave.core.failures.BatchFailures;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.junit.JUnitStory;
import org.jbehave.core.model.Story;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.steps.CandidateSteps;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.NullStepMonitor;
import org.jbehave.core.steps.StepMonitor;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.github.valfirst.jbehave.junit.monitoring.JUnitDescriptionGenerator;
import com.github.valfirst.jbehave.junit.monitoring.JUnitScenarioReporter;

public class SpringReportingRunner extends SpringJUnit4ClassRunner{


private Embedder configuredEmbedder;
private Configuration configuration;
private int numberOfTestCases;
private Description rootDescription;
private ConfigurableEmbedder configurableEmbedder;

public SpringReportingRunner(Class<? extends ConfigurableEmbedder> testClass)
throws InitializationError, ReflectiveOperationException {
super(testClass);
super.getTestContextManager();
try {
configurableEmbedder =(ConfigurableEmbedder) super.createTest();
} catch (Exception e) {
throw new RuntimeException(e);
}
configuredEmbedder = configurableEmbedder.configuredEmbedder();
configuration = configuredEmbedder.configuration();

List<String> storyPaths = getStoryPaths(testClass);

StepMonitor originalStepMonitor = configuration.stepMonitor();
configuration.useStepMonitor(new NullStepMonitor());
List<Description> storyDescriptions = buildDescriptionFromStories(storyPaths);
configuration.useStepMonitor(originalStepMonitor);

rootDescription = Description.createSuiteDescription(testClass);
for (Description storyDescription : storyDescriptions) {
rootDescription.addChild(storyDescription);
}
}

@Override
public Description getDescription() {
return rootDescription;
}

@Override
public int testCount() {
return numberOfTestCases;
}

/**
* Returns a {@link Statement}: Call {@link #runChild(Object, RunNotifier)}
* on each object returned by {@link #getChildren()} (subject to any imposed
* filter and sort)
*/
@Override
protected Statement childrenInvoker(final RunNotifier notifier) {
return new Statement() {
@Override
public void evaluate() {
JUnitScenarioReporter junitReporter = new JUnitScenarioReporter(
notifier, numberOfTestCases, rootDescription, configuration.keywords());
// tell the reporter how to handle pending steps
junitReporter.usePendingStepStrategy(configuration
.pendingStepStrategy());

addToStoryReporterFormats(junitReporter);

try {
configurableEmbedder.run();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
};
}

public static EmbedderControls recommendedControls(Embedder embedder) {
return embedder.embedderControls()
// don't throw an exception on generating reports for failing stories
.doIgnoreFailureInView(true)
// don't throw an exception when a story failed
.doIgnoreFailureInStories(true)
// .doVerboseFailures(true)
.useThreads(1);
}

private List<String> getStoryPaths(Class<? extends ConfigurableEmbedder> testClass)
throws ReflectiveOperationException {
if (JUnitStories.class.isAssignableFrom(testClass)) {
return getStoryPathsFromJUnitStories(testClass);
} else if (JUnitStory.class.isAssignableFrom(testClass)) {
return Arrays.asList(configuration.storyPathResolver().resolve(testClass));
} else {
throw new IllegalArgumentException(
"Only ConfigurableEmbedder of types JUnitStory and JUnitStories is supported");
}
}

@SuppressWarnings("unchecked")
private List<String> getStoryPathsFromJUnitStories(
Class<? extends ConfigurableEmbedder> testClass)
throws ReflectiveOperationException {
Method method = makeStoryPathsMethodPublic(testClass);
return ((List<String>) method.invoke(configurableEmbedder, (Object[]) null));
}

@SuppressWarnings("unchecked")
private static Method makeStoryPathsMethodPublic(Class<? extends ConfigurableEmbedder> clazz)
throws NoSuchMethodException {
try {
Method method = clazz.getDeclaredMethod("storyPaths", (Class[]) null);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
Class<?> superclass = clazz.getSuperclass();
if (superclass != null && ConfigurableEmbedder.class.isAssignableFrom(superclass)) {
return makeStoryPathsMethodPublic((Class<? extends ConfigurableEmbedder>) superclass);
}
throw e;
}
}

private List<CandidateSteps> getCandidateSteps() {
List<CandidateSteps> candidateSteps;
InjectableStepsFactory stepsFactory = configurableEmbedder.stepsFactory();
if (stepsFactory != null) {
candidateSteps = stepsFactory.createCandidateSteps();
} else {
candidateSteps = configuredEmbedder.candidateSteps();
if (candidateSteps == null || candidateSteps.isEmpty()) {
candidateSteps = configuredEmbedder.stepsFactory().createCandidateSteps();
}
}
return candidateSteps;
}

private void addToStoryReporterFormats(JUnitScenarioReporter junitReporter) {
StoryReporterBuilder storyReporterBuilder = configuration
.storyReporterBuilder();
StoryReporterBuilder.ProvidedFormat junitReportFormat = new StoryReporterBuilder.ProvidedFormat(
junitReporter);
storyReporterBuilder.withFormats(junitReportFormat);
}

private List<Description> buildDescriptionFromStories(List<String> storyPaths) {
JUnitDescriptionGenerator descriptionGenerator = new JUnitDescriptionGenerator(
getCandidateSteps(), configuration);
List<Description> storyDescriptions = new ArrayList<>();

addSuite(storyDescriptions, "BeforeStories");
storyDescriptions.addAll(descriptionGenerator.createDescriptionFrom(createPerformableTree(storyPaths)));
addSuite(storyDescriptions, "AfterStories");

numberOfTestCases += descriptionGenerator.getTestCases();

return storyDescriptions;
}

private PerformableTree createPerformableTree(List<String> storyPaths) {
BatchFailures failures = new BatchFailures(configuredEmbedder.embedderControls().verboseFailures());
PerformableTree performableTree = new PerformableTree();
RunContext context = performableTree.newRunContext(configuration, configuredEmbedder.stepsFactory(),
configuredEmbedder.embedderMonitor(), configuredEmbedder.metaFilter(), failures);
performableTree.addStories(context, storiesOf(performableTree, storyPaths));
return performableTree;
}

private List<Story> storiesOf(PerformableTree performableTree, List<String> storyPaths) {
List<Story> stories = new ArrayList<>();
for (String storyPath : storyPaths) {
stories.add(performableTree.storyOfPath(configuration, storyPath));
}
return stories;
}

private void addSuite(List<Description> storyDescriptions, String name) {
storyDescriptions.add(Description.createTestDescription(Object.class,
name));
numberOfTestCases++;
}
}
```
### spring support useage
```
import static org.jbehave.core.io.CodeLocations.codeLocationFromPath;

import java.util.List;

import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.CrossReference;
import org.jbehave.core.reporters.Format;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.spring.SpringStepsFactory;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ActiveProfiles;

@RunWith(SpringReportingRunner.class)
@SpringBootTest(properties = { "zookeeper.address=192.168.1.14:12181", "application.host=127.0.0.1",
"application.port=90", "profile=dev" })
@AutoConfigureMockMvc
@ActiveProfiles(profiles = "dev")
public class Test2 extends JUnitStories {
@Autowired
protected ApplicationContext context;
@Override
public InjectableStepsFactory stepsFactory() {
if (super.hasStepsFactory()) {
return super.stepsFactory();
}
return new SpringStepsFactory(configuration(), context);
}

@Override
public Configuration configuration() {
if (super.hasConfiguration()) {
return super.configuration();
}
Configuration configuration = new MostUsefulConfiguration().useStoryReporterBuilder(new StoryReporterBuilder()
.withDefaultFormats().withFormats(Format.CONSOLE, Format.TXT, Format.HTML, Format.XML)
.withCrossReference(new CrossReference()).withFailureTrace(true));
return configuration;
}

@Override
protected List<String> storyPaths() {
List<String> storyPaths = new StoryFinder().findPaths(codeLocationFromPath("src/test/resources"), "**/*.story",
"");
return storyPaths;
}




}
```
Credits
=================================
This project is based on the original implementation by Mark Burnett, located at http://code.google.com/p/jbehave-junit-monitor/ which worked with earlier versions of JBehave.
Expand Down