Comments (3)
Well, yes, you're right. The SpringJUnit4ClassRunner uses three test execution listeners:
org.springframework.test.context.support.DependencyInjectionTestExecutionListener
org.springframework.test.context.support.DirtiesContextTestExecutionListener
org.springframework.test.context.transaction.TransactionalTestExecutionListener
These default test execution listeners are defined in org.springframework.test.context.TestContextManager
. The SpringJUnitReportingRunner
only calls prepareTestInstance()
on the TextContextManager
instance which delegates the call to the test execution listeners and this method is not overridden by the TransactionalTestExecutionListener
. TransactionalTestExecutionListener
's magic happens in beforeTestMethod()
and afterTestMethod()
but the SpringJUnitReportingRunner
is not using them.
from jbehave-junit-runner.
@visusnet
Thank you for your quick response, very detailed explanation π
I know JBehave
(and general BDD implementations) focus on acceptance tests, so it's often unnecessary to support transaction rollback. But in some cases, it is required to rollback transaction after each test for clean data.
By your given information, I tried to find a solution that could make SpringJUnitReportingRunner
works well with Spring Transactional
annotation. Lucky I found one, the following is my snippets:
- JUnit-runnable entry-point to run multiple stories: NewContactServiceBDDTest.java
βΉοΈ override run() method with addition of Spring Transactional
annotation
@RunWith(SpringJUnitReportingRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring-servlet.xml")
public class NewContactServiceBDDTest extends JUnitStories {
@Autowired
private ApplicationContext context;
@Override
public Configuration configuration() {
return new MostUsefulConfiguration();
}
public InjectableStepsFactory stepsFactory() {
return new SpringStepsFactory(configuration(), context);
}
@Override
protected List<String> storyPaths() {
return Arrays.asList("net/viralpatel/contact/service/add_contact.story");
}
@Transactional
public void run() throws Throwable {
super.run();
}
}
- Modified runner: SpringJUnitReportingRunner.java
βΉοΈ override JUnitReportingRunner.run(RunNotifier notifier) method, add new org.junit.runner.notification.RunListener
to notifier. It will invoke org.springframework.test.context.TestContextManager
beforeTestMethod(...) and afterTestMethod(...) to fire TransactionalTestExecutionListener
execution
public class SpringJUnitReportingRunner extends JUnitReportingRunner {
SpringJunit4ClassRunnerExecutor executor;
ConfigurableEmbedder ce;
public SpringJUnitReportingRunner(Class<? extends ConfigurableEmbedder> testClass) throws Throwable {
super(testClass);
}
@Override
protected void prepareConfigurableEmbedder(Class<? extends ConfigurableEmbedder> testClass, ConfigurableEmbedder configurableEmbedder) throws Exception {
ce = configurableEmbedder;
executor = new SpringJunit4ClassRunnerExecutor(testClass);
executor.getHiddenTestContextManager().prepareTestInstance(configurableEmbedder);
}
@Override
public void run(RunNotifier notifier) {
notifier.addListener(new RunListener() {
public void testRunStarted(Description description) throws Exception {
System.err.println("testRunStarted");
executor.getHiddenTestContextManager().beforeTestMethod(ce, description.getTestClass().getDeclaredMethod("run", new Class[] {}));
}
public void testRunFinished(Result result) throws Exception {
System.err.println("testRunFinished");
executor.getHiddenTestContextManager().afterTestMethod(ce, ce.getClass().getDeclaredMethod("run", new Class[] {}), new Throwable("error"));
}
});
super.run(notifier);
}
private static class SpringJunit4ClassRunnerExecutor extends SpringJUnit4ClassRunner {
public SpringJunit4ClassRunnerExecutor(Class<?> clazz) throws InitializationError {
super(clazz);
}
public TestContextManager getHiddenTestContextManager() {
return getTestContextManager();
}
}
}
- Important: To support Spring transaction rollback, must change execution mechanism of
org.jbehave.core.embedder.StoryManager
to SEQUENCE (it means we won't usejava.util.concurrent.ExecutorService
to run stories concurrency, but one by one) - Now, everything works well, transaction rollback automatically after each test/ stories
βΊοΈ
The above snippets are only my draft, I know it's not a good solution, just makes JBehave
, Spring
and JUnit
work together, Could you please investigate and make it better? I believe you can do it π
I will follow you!
from jbehave-junit-runner.
Wow, that surely looks like a promising approach. However, there are some drawbacks (for example: usage of reflection, the necessary manual override of the run()
method in a class that inherits from JUnitStories
, instantiating Throwable
). I think the additional RunListener
is the important step. What's bothering me most is the fact, that you need to provide a run method that is annotated with @Transactional
but then again: You need to state somewhere that you want to enable transaction support (maybe on class level?).
During further investigation, I noticed that a @Transactional
annotation on class level should work. Here is why:
- The
TransactionalTestExecutionListener
uses an instance ofAnnotationTransactionAttributeSource
to get information about transactions (rollback strategy, transaction: yes/no, a.s.o.). See for example: http://grepcode.com/file/repo1.maven.org/maven2/org.springframework/spring-test/3.0.1.RELEASE/org/springframework/test/context/transaction/TransactionalTestExecutionListener.java#131 - The
AnnotationTransactionAttributeSource
has a list of annotation parsers. One element of this list is an instance ofSpringTransactionAnnotationParser
. Somewhere deep within the execution, you should end up here: http://grepcode.com/file/repo1.maven.org/maven2/org.springframework/spring-tx/3.0.1.RELEASE/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java#150. - So basically, if there is no
@Transactional
on the method, the transaction mechanism tries to detect an annotation on class level within the call ofbeforeTestMethod()
.
Unfortunately, I don't see a way around the reflection magic... Mhmm...
from jbehave-junit-runner.
Related Issues (20)
- Move to JUnit 5
- Suggestion on using this with WeldAnnotatedEmbedderRunner
- Handle RestartingScenarioFailure HOT 1
- Filtering out all scenarios in the story file causes NPE HOT 9
- How to make Junit runner read limited words from scenario and create .xml file from it. HOT 4
- I cannot start single scenario in eclipse HOT 5
- NPE on Failure.getTestHeader(Failure.java:44) when step throws assert in Lifecycle>After>FAILURE
- Using JUnitReportingRunner with pitest HOT 2
- Export the report in any other format
- Tests failing on master HOT 2
- How to generate the jbehave-surefire.xml file with parametrised examples HOT 5
- Inconsistent versions HOT 10
- Throws RuntimeException on scenario failure instead of java.lang.AssertionError HOT 2
- jbehave-junit-runner by maven and not from IDE HOT 7
- Jbehave-junit-runner incorrectly shows scenarios being executed when mata keywords applied in Jbehave 4 version HOT 13
- bad checksum on repo1.maven.org HOT 1
- Not showing correct test names in IntelliJ HOT 7
- Customize output monitor HOT 1
- Comments in scenario are reported as ignored HOT 10
- Remove fix for special IntelliJ handling
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jbehave-junit-runner.