Skip to content

Instantly share code, notes, and snippets.

@vkorobkov
Created October 31, 2018 09:53
Show Gist options
  • Save vkorobkov/b96d9706deef9bdb7366f0d4a457922d to your computer and use it in GitHub Desktop.
Save vkorobkov/b96d9706deef9bdb7366f0d4a457922d to your computer and use it in GitHub Desktop.
Make JUnit5 using the same spring context in nested classes/tests
import groovy.transform.AnnotationCollector
import org.junit.jupiter.api.Tag
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
@SameSpringContextSupport
@SpringBootTest
@AutoConfigureMockMvc
@AnnotationCollector
@interface IntegrationTest {
}
import groovy.transform.CompileStatic
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.extension.BeforeAllCallback
import org.junit.jupiter.api.extension.ExtensionContext
import org.springframework.test.context.TestContextManager
import org.springframework.test.context.junit.jupiter.SpringExtension
/*
* Exists as a temporary work around until this is fixed:
* https://jira.spring.io/browse/SPR-16595
*/
@CompileStatic
class SameSpringContextExt implements BeforeAllCallback {
private static final ExtensionContext.Namespace NAMESPACE =
ExtensionContext.Namespace.create([SpringExtension] as Object[])
@Override
void beforeAll(ExtensionContext context) throws Exception {
if (!isNested(context)) {
return
}
def store = context.root.getStore(NAMESPACE)
def testClass = context.requiredTestClass
while (context != null && store.get(context.requiredTestClass, TestContextManager) == null) {
context = context.parent.orElse(null)
}
store.put(testClass, store.get(context.requiredTestClass, TestContextManager))
}
private static isNested(ExtensionContext context) {
context.requiredTestClass.annotations.any { it instanceof Nested }
}
}
import org.junit.jupiter.api.extension.ExtendWith
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
/*
* This wrapper prevents changing the order of @ExtendWith repeatable annotation, because it is grouping automatically
* into @Extensions parent annotation which moves strictly after @SpringBootTest(which has
* @ExtendWith({SpringExtension.class}) inside).
*
* The order is critical since we want to call SameSpringContextExt strictly before SpringExtension, so every nested
* JUnit test reuse the same application context as in outer test class
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(SameSpringContextExt)
@interface SameSpringContextSupport {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment