-
Notifications
You must be signed in to change notification settings - Fork 38.4k
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
SPR-10217 Implement JUnit 4 Support using Rules #222
Conversation
See SPR-7731 instead of SPR-10217. |
just a quick note that the profile check could make use of assumptions: from the org.junit.Assume javadoc "The default JUnit runner treats tests with failing assumptions as ignored" assumeTrue("required profile not active", ProfileValueUtils.isTestEnabledInThisEnvironment(getTestClass().getJavaClass())); should do the trick |
also it seems safe to stick with MethodRule - @deprecated has been removed as of junit 4.11 due to numerous user requests and the junit team has no intention to deprecate it again: https://github.com/KentBeck/junit/pull/519 |
In theory we could have single rule that implements both public class SampleTests {
@ClassRule
public static final SpringJUnitRule CLASS_RULE = new SpringJUnitRule();
@Rule
public MethodRule methodRule = CLASS_RULE;
} |
@eeichinger good idea I updated the pull request |
Currently JUnit 4 support is provided by SpringJUnit4ClassRunner which is a custom BlockJUnit4ClassRunner. There is no support for using other runners like Theories or Parameterized or 3rd party runners like MockitoJUnitRunner. A runner based approach does not seem to offer much promise as runners are not composable, a custom Spring version of every runner has to be developed and maintained. With JUnit 4.9+ the preferred way to implement such behavior is to use rules. Unlike runners there can be several ones of them and they can be composed. In theory TestExecutionListener could be deprecated and be replaced with standard JUnit rules but this seems to be a bit on the drastic side. This proposed implementation is using both a class rule and a method rule. The class rule creates the TestContextManager, runs all the class level callbacks and class level checks. The method rule runs all the instance level callbacks and method level checks. I did not see a way to implement the current functionality offered by SpringJUnit4ClassRunner using only one rule. Using two rules has the advantage that the implementation is cleaner because it better separates the concerns. However it has the disadvantage that it's harder to set up because both a method rule and a class rule are needed. This also increases the potential for misconfiguration. The method rule has to be a MethodRule instead of a TestRule because only the former has access to the test object with we need to perform injection. This interface used to be deprecated once but doesn't seem to be anymore. This creates a certain risk that it will be deprectated again and potentially be remvoed in the future. An additional drawback is that MethodRule unlike TestRule can only be defined in fields and not methods. This is an unfortunate consequence of the implementation of org.junit.runners.model.TestClass. As JUnit does not do Field#setAccessible(true) this means that tests will have to be defined in public fields. Another minor issue is that tests not run because of IfProfileValue will still show up in the Eclipse test tree, just blank. In conclusion while the given implementation has some downsides I don't see any other possible implementations given the current state of affairs in JUnit. - Add SpringJUnitClassRule for all the class level processing - Add SpringJUnitMethodRule for all the method level processing - Add tests for the rules SPR-10217
@marschall cool. not sure how many people are actually using @BeforeClass, but I mostly don't. so it's a bit of an inconvenience always having to the define both rules. Asfaik you can safely create two separate instances of TestContextManager as they're accessing the same static contextcache anyway. This way one has to define the @ClassRule only if you really need it for @BeforeClass Other than that I've taken your code and use it 2 projects already, works like a charme! |
@eeichinger also And thanks for testing. Edit: |
the TestExecutionListeners should be stateless anyway, so no problem. But I see your point that TestExecutionListeners might expect before/afterTestClass to be called before before/afterTest get called. None of the default TestExecutionListeners do so, but custom ones might break. Which I'd say leaves it up to the user to configure the @ClassRule if his test setups require so just wondering: does the junit api allow for a classrule to register an instance rule? |
send a pull request... :) |
The comments in SpringJUnitMethodRule mention that ExpectedException is not supported; is that indeed true? If so, can you elaborate a bit? |
The Javadoc for If you take a look at the imports in So fear not: JUnit's |
For what it's worth, |
@marschall and @eeichinger, thanks so much for all of your ideas and collaboration on this! I've just committed support for this in Spring Framework 4.2 RC1 here: d1b1c4f. Cheers, Sam |
Though... perhaps I should attribute the |
Currently JUnit 4 support is provided by SpringJUnit4ClassRunner which
is a custom BlockJUnit4ClassRunner. There is no support for using other
runners like Theories or Parameterized or 3rd party runners like
MockitoJUnitRunner. A runner based approach does not seem to offer much
promise as runners are not composable, a custom Spring version of every
runner has to be developed and maintained.
With JUnit 4.9+ the preferred way to implement such behavior is to use
rules. Unlike runners there can be several ones of them and they can be
composed. In theory TestExecutionListener could be deprecated and be
replaced with standard JUnit rules but this seems to be a bit on the
drastic side.
This proposed implementation is using both a class rule and a method
rule. The class rule creates the TestContextManager, runs all the class
level callbacks and class level checks. The method rule runs all the
instance level callbacks and method level checks. I did not see a way
to implement the current functionality offered by
SpringJUnit4ClassRunner using only one rule.
Using two rules has the advantage that the implementation is cleaner
because it better separates the concerns. However it has the
disadvantage that it's harder to set up because both a method rule and
a class rule are needed. This also increases the potential for
misconfiguration.
The method rule has to be a MethodRule instead of a TestRule because
only the former has access to the test object with we need to perform
injection. This interface used to be deprecated once but doesn't seem
to be anymore. This creates a certain risk that it will be deprectated
again and potentially be remvoed in the future. An additional drawback
is that MethodRule unlike TestRule can only be defined in fields and
not methods. This is an unfortunate consequence of the implementation
of org.junit.runners.model.TestClass. As JUnit does not do
Field#setAccessible(true) this means that tests will have to be defined
in public fields.
Another minor issue is that tests not run because of IfProfileValue
will still show up in the Eclipse test tree, just blank.
In conclusion while the given implementation has some downsides I don't
see any other possible implementations given the current state of
affairs in JUnit.
SPR-10217