From 4c728ae18e2c205fd8632b00ee2daa3530f19b5d Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Thu, 12 Feb 2026 21:49:07 +0100 Subject: [PATCH] testFramework [platform]: Fail test when a fixture throws an exception. Currently, exceptions thrown by fixture teardowns are ignored as they are thrown in background scope. We collect them and report them GitOrigin-RevId: 8cfdff26574e10adfc954b02f53c3fb032cfaf0d --- .../src/fixture/TestFixtureExtension.kt | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/platform/testFramework/junit5/src/fixture/TestFixtureExtension.kt b/platform/testFramework/junit5/src/fixture/TestFixtureExtension.kt index 81a1ebcca294..63b8ba0e1449 100644 --- a/platform/testFramework/junit5/src/fixture/TestFixtureExtension.kt +++ b/platform/testFramework/junit5/src/fixture/TestFixtureExtension.kt @@ -5,6 +5,11 @@ import com.intellij.platform.eel.EelApi import com.intellij.platform.util.coroutines.childScope import com.intellij.testFramework.TestLoggerFactory import com.intellij.testFramework.junit5.fixture.EelForFixturesProvider.Companion.getEelForParametrizedTestProvider +import com.intellij.testFramework.junit5.impl.TypedStoreKey +import com.intellij.testFramework.junit5.impl.TypedStoreKey.Companion.get +import com.intellij.testFramework.junit5.impl.TypedStoreKey.Companion.remove +import com.intellij.testFramework.junit5.impl.TypedStoreKey.Companion.set +import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.DelicateCoroutinesApi @@ -36,6 +41,9 @@ internal class TestFixtureExtension : BeforeAllCallback, AfterEachCallback, AfterAllCallback, InvocationInterceptor { + private companion object { + val exceptionsKey = TypedStoreKey.createKey() + } override fun beforeAll(context: ExtensionContext) { before(context, static = true) @@ -88,8 +96,13 @@ internal class TestFixtureExtension : BeforeAllCallback, TestLoggerFactory.onFixturesInitializationStarted(static) + val exceptionHandler = CoroutineExceptionHandler { _, exception -> + context[exceptionsKey] = exception + throw exception + } + @OptIn(DelicateCoroutinesApi::class) - val testScope = GlobalScope.childScope(context.displayName) + val testScope = GlobalScope.childScope(context.displayName, exceptionHandler) val pendingFixtures = ArrayList>() val classToTestInstance = collectTestInstances(context) @@ -125,6 +138,12 @@ internal class TestFixtureExtension : BeforeAllCallback, after(context, static = false) } after(context, static = true) + // Throw unprocessed exceptions thrown by fixtures to break the test + val exception = context[exceptionsKey] + context.remove(exceptionsKey) + if (exception != null) { + throw exception + } } private fun after(context: ExtensionContext, static: Boolean) {