From 910146cd017057579272c0849621f2ab807726e4 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Tue, 9 Jul 2024 19:36:29 +0000 Subject: [PATCH] JUnit5 framework: Support fields declared in parent class. Although inheritance is not recommended and even redundant with JUnit5 extensions, we still have to support it. Merge-request: IJ-MR-139345 Merged-by: Ilya Kazakevich GitOrigin-RevId: 812e828c2c4232fd7dd92bafe58001d78497fd48 --- .../src/fixture/TestFixtureExtension.kt | 15 ++++---- .../test/showcase/JUnit5InheritanceFixture.kt | 37 +++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 platform/testFramework/junit5/test/showcase/JUnit5InheritanceFixture.kt 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