- 
                Notifications
    You must be signed in to change notification settings 
- Fork 38.8k
Description
Phil Webb opened SPR-9232 and commented
Status Quo
The order in which JUnit rules are run was changed between Spring 3.0 and 3.1 to match JUnit (see #12361). As a side effect of this, @Rule callbacks (such as the one developed for #11259) are now executed after the callbacks in TestExecutionListeners.  This can be problematic if your rule is running within a transaction as the TransactionalTestExecutionListener will perform the rollback before the rule runs. The opposite may also be true: a transaction might not be started before the rule runs.
Current Implementation of SpringJUnit4ClassRunner.methodBlock()
Statement statement = methodInvoker(frameworkMethod, testInstance);
statement = possiblyExpectingExceptions(frameworkMethod, testInstance, statement);
statement = withBefores(frameworkMethod, testInstance, statement);
statement = withAfters(frameworkMethod, testInstance, statement);
statement = withRulesReflectively(frameworkMethod, testInstance, statement);
statement = withPotentialRepeat(frameworkMethod, testInstance, statement);
statement = withPotentialTimeout(frameworkMethod, testInstance, statement);Goals
Ideally, one could argue that in most circumstances the TransactionalTestExecutionListener should always be the first and last thing to run.
Deliverables
- Consider changing the SpringJUnit4ClassRunner.methodBlock()method to callTestExecutionListenercallbacks outside of JUnit@Beforecalls, something like:
Statement statement = methodInvoker(frameworkMethod, testInstance);
statement = possiblyExpectingExceptions(frameworkMethod, testInstance, statement);
statement = withTestExecutionListenerBefores(frameworkMethod, testInstance, statement);
statement = withTestExecutionListenerAfters(frameworkMethod, testInstance, statement);
statement = withRulesReflectively(frameworkMethod, testInstance, statement);
statement = withBefores(frameworkMethod, testInstance, statement);
statement = withAfters(frameworkMethod, testInstance, statement);
statement = withPotentialRepeat(frameworkMethod, testInstance, statement);
statement = withPotentialTimeout(frameworkMethod, testInstance, statement);This would ensure that the before and after callbacks of TransactionalTestExecutionListener (and any TestExecutionListener) get called around the @Rule.
Alternatives
Another option would be to introduce a RuleAwareTestExecutionListener interface that adds beforeRules() and afterRules() methods and have TransactionalTestExecutionListener implement this interface as well (or possibly instead of) TestExecutionListener.
Affects: 3.1.1
Issue Links:
- Provide @Rule alternative to SpringJUnit4ClassRunner [SPR-7731] #12387 Provide @Rulealternative to SpringJUnit4ClassRunner ("depends on")
- jUnit 4 and @Rule execution order [SPR-7705] #12361 jUnit 4 and @Ruleexecution order
4 votes, 6 watchers