diff --git a/platform/testFramework/junit5/src/fixture/TestFixtureExtension.kt b/platform/testFramework/junit5/src/fixture/TestFixtureExtension.kt index bafefbf9fa4d..66f9aec5278a 100644 --- a/platform/testFramework/junit5/src/fixture/TestFixtureExtension.kt +++ b/platform/testFramework/junit5/src/fixture/TestFixtureExtension.kt @@ -5,8 +5,10 @@ import com.intellij.platform.util.coroutines.childScope import kotlinx.coroutines.* import org.jetbrains.annotations.TestOnly import org.junit.jupiter.api.extension.* -import java.lang.reflect.Field +import org.junit.platform.commons.support.HierarchyTraversalMode +import org.junit.platform.commons.support.ReflectionSupport import java.lang.reflect.Modifier +import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull @TestOnly @@ -30,13 +32,10 @@ internal class TestFixtureExtension : BeforeAllCallback, @OptIn(DelicateCoroutinesApi::class) val testScope = GlobalScope.childScope(context.displayName) val pendingFixtures = ArrayList>() - for (field: Field in testClass.declaredFields) { - if (!TestFixture::class.java.isAssignableFrom(field.type)) { - continue - } - if (Modifier.isStatic(field.modifiers) != static) { - continue - } + val fields = ReflectionSupport.findFields(testClass, Predicate { field -> + TestFixture::class.java.isAssignableFrom(field.type) && Modifier.isStatic(field.modifiers) == static + }, HierarchyTraversalMode.TOP_DOWN) + for (field in fields) { field.isAccessible = true val fixture = field.get(testInstance) as TestFixtureImpl<*> pendingFixtures.add(fixture.init(testScope, context.uniqueId)) diff --git a/platform/testFramework/junit5/test/showcase/JUnit5InheritanceFixture.kt b/platform/testFramework/junit5/test/showcase/JUnit5InheritanceFixture.kt new file mode 100644 index 000000000000..78693fde142a --- /dev/null +++ b/platform/testFramework/junit5/test/showcase/JUnit5InheritanceFixture.kt @@ -0,0 +1,37 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.testFramework.junit5.showcase + +import com.intellij.testFramework.junit5.TestApplication +import com.intellij.testFramework.junit5.fixture.disposableFixture +import com.intellij.testFramework.junit5.fixture.moduleFixture +import com.intellij.testFramework.junit5.fixture.projectFixture +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Test + +/** + * Support fields declared at parent level. + * Implementation inheritance is a bad pattern, avoid it and use extensions instead + */ +@TestApplication +open class AbstractTestCase { + companion object { + val classLevelDisposable = disposableFixture() + } + + protected val testLevelProject = projectFixture() +} + +class JUnit5InheritanceFixture : AbstractTestCase() { + private val moduleFixture = testLevelProject.moduleFixture() + + @Test + fun ensureParentFixturesInitialized() { + assertNotNull(classLevelDisposable.get()) + assertNotNull(testLevelProject.get()) + } + + @Test + fun ensureChildrenInheritParent() { + assertNotNull(moduleFixture.get()) + } +} \ No newline at end of file