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

Support nested test classes with SpringClassRule & SpringMethodRule [SPR-14150] #18722

Closed
3 tasks done
spring-projects-issues opened this issue Apr 12, 2016 · 4 comments
Closed
3 tasks done
Assignees
Labels
in: test Issues in the test module status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Apr 12, 2016

Benoit AVERTY opened SPR-14150 and commented

Status Quo

The Spring TestContext Framework has traditionally supported only top-level or static nested test classes. With support for @Nested test classes in JUnit 5 and custom runners in JUnit 4, however, there is increased need to support nested non-static test classes (i.e., inner classes).

Deliverables

  1. Introduce support for loading a test ApplicationContext via @ContextConfiguration and related annotations for a nested test class.
    • This already works without modifications to the existing code base: a nested (i.e., non-static inner) test class is still a Class, so the TestContext framework doesn't need to do anything special here.
  2. Ensure that JUnit Jupiter based @Nested test classes work with the TestContext framework.
  3. Ensure that SpringClassRule and SpringMethodRule work in conjunction with JUnit 4 based runners that support nested test classes.
    • Introduced a workaround which is documented in this issue's comments section.

JUnit 4 Hierarchical Runners

When using the @Rule and @ClassRule classes SpringMethodRule and SpringClassRule in conjunction with a custom JUnit 4 Runner that allows one to use nested classes to create hierarchical tests, the tests in subclasses fail with an IllegalStateException.

Examples of hierarchical runners:

The second one doesn't have the same error, but I'm guessing the problem is similar.


java.lang.IllegalStateException: Failed to find 'public static final SpringClassRule' field in test class [com.example.unit.testing.application.PlacingOrderTest$WithExistingCustomer]. Consult the javadoc for SpringClassRule for details.
	at org.springframework.test.context.junit4.rules.SpringMethodRule.validateSpringClassRuleConfiguration(SpringMethodRule.java:233)
	at org.springframework.test.context.junit4.rules.SpringMethodRule.apply(SpringMethodRule.java:143)
	at de.bechte.junit.runners.context.statements.builder.HierarchicalRunRulesStatementBuilder.createStatement(HierarchicalRunRulesStatementBuilder.java:42)
	at de.bechte.junit.runners.context.processing.MethodExecutor.run(MethodExecutor.java:80)
	at de.bechte.junit.runners.context.processing.MethodExecutor.run(MethodExecutor.java:57)
	at de.bechte.junit.runners.context.statements.RunChildren.evaluate(RunChildren.java:38)
	at de.bechte.junit.runners.context.statements.RunAll.evaluate(RunAll.java:27)
	at de.bechte.junit.runners.context.statements.StatementExecutor.execute(StatementExecutor.java:28)
	at de.bechte.junit.runners.context.HierarchicalContextRunner.run(HierarchicalContextRunner.java:134)
	at de.bechte.junit.runners.context.processing.ContextExecutor.run(ContextExecutor.java:26)
	at de.bechte.junit.runners.context.processing.ContextExecutor.run(ContextExecutor.java:15)
	at de.bechte.junit.runners.context.statements.RunChildren.evaluate(RunChildren.java:38)
	at de.bechte.junit.runners.context.statements.RunAll.evaluate(RunAll.java:27)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.springframework.test.context.junit4.statements.ProfileValueChecker.evaluate(ProfileValueChecker.java:103)
	at org.springframework.test.context.junit4.rules.SpringClassRule$TestContextManagerCacheEvictor.evaluate(SpringClassRule.java:248)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at de.bechte.junit.runners.context.statements.StatementExecutor.execute(StatementExecutor.java:28)
	at de.bechte.junit.runners.context.HierarchicalContextRunner.run(HierarchicalContextRunner.java:134)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

The exception makes sense because the nested class indeed doesn't have the static SpringClassRule. But it can't have it because the nested class isn't static. Moreover, I'm not sure it would need it because the rule would be evaluated twice.


Affects: 4.2.5

Issue Links:

Referenced from: commits ab7b5e5, e574820

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

Thanks for raising the issue.

Is it possible to correct this behavior or find a workaround ?

Nested test classes are rather new in the world of JUnit. Thus, there is currently no work-around for this scenario; however, I will look into a general solution, especially since @Nested test classes make up a prominent feature of JUnit 5.

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

Changed issue title to reflect the fact that only the combination of SpringClassRule and SpringMethodRule appears not to be supported out of the box.

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

Update

I have some good news!

I actually discovered a workaround and pushed an example to master in GitHub commit ab7b5e5.

Here's the important part:

The trick is to have inner test classes extend a class that properly declares the SpringClassRule and SpringMethodRule. The SpringRuleConfigurer in this commit serves as an example.

Note, however, that each such nested test class must declare its own @ContextConfiguration. Furthermore, TestExecutionListeners in the Spring TestContext Framework are not applied to the enclosing instance of such an inner test class, meaning that @Autowired fields in the enclosing instance will not be injected, etc.

And here's the source code for SpringRuleConfigurer, which you are free to copy and use in your projects.

public abstract class SpringRuleConfigurer {

	@ClassRule
	public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();

	@Rule
	public final SpringMethodRule springMethodRule = new SpringMethodRule();

}

Kaidjin, please let me know if this workaround solves your immediate problems.

Cheers,

Sam

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

Resolving this issue as Works as Designed since a workaround has been provided that overcomes the restrictions imposed by JUnit 4 and the Java language.

@spring-projects-issues spring-projects-issues added status: declined A suggestion or change that we don't feel we should currently apply in: test Issues in the test module type: enhancement A general enhancement labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 5.0 M2 milestone Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module status: declined A suggestion or change that we don't feel we should currently apply type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants