如何在@AfterEach执行前拦截JUnit 5中@BeforeEach的异常?
JUnit 5中@BeforeEach异常无法在@AfterEach前拦截的问题及解决方案探索
问题概述
JUnit 5存在一个问题:当@BeforeEach方法抛出异常时,无法在调用@AfterEach方法前对该异常进行拦截处理。@AfterTestExecutionCallback扩展仅能处理@Test方法执行过程中出现的异常,对@BeforeEach方法的异常无能为力,导致初始化阶段的异常无法被及时拦截。
复现代码
LogsWatcher.kt
import org.junit.jupiter.api.extension.* import org.junit.jupiter.api.fail open class LogsWatcher : TestWatcher, BeforeEachCallback, AfterEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback { override fun testFailed(context: ExtensionContext, cause: Throwable?) { failedLogs(context, object {}.javaClass.enclosingMethod.name) super.testFailed(context, cause) } open fun failedLogs(context: ExtensionContext?, methodName: String) { println("$methodName started") val testFailed = context?.executionException?.isPresent ?: fail("Test has no context") if (testFailed) { println(" $methodName: failed") } } override fun beforeEach(context: ExtensionContext?) { failedLogs(context, object {}.javaClass.enclosingMethod.name) } override fun afterEach(context: ExtensionContext?) { failedLogs(context, object {}.javaClass.enclosingMethod.name) } override fun beforeTestExecution(context: ExtensionContext?) { failedLogs(context, object {}.javaClass.enclosingMethod.name) } override fun afterTestExecution(context: ExtensionContext?) { failedLogs(context, object {}.javaClass.enclosingMethod.name) } }
MyTest.kt
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(LogsWatcher::class) class MyTest { @BeforeEach fun preCondition(){ println("@BeforeEach start") Assertions.assertTrue(false) println("@BeforeEach stop") } @Test fun myTest(){ println("Test start") Assertions.assertTrue(false) println("Test stop") } @AfterEach fun postCondition1(){ println("@AfterEach 1") } @AfterEach fun postCondition2(){ println("@AfterEach 2") } }
执行输出
当@BeforeEach执行失败时的输出
beforeEach started @BeforeEach start @AfterEach 1 @AfterEach 2 afterEach started afterEach: failed testFailed started testFailed: failed
当@Test执行失败时的输出
beforeEach started @BeforeEach start @BeforeEach stop beforeTestExecution started Test start afterTestExecution started afterTestExecution: failed @AfterEach 1 @AfterEach 2 afterEach started afterEach: failed testFailed started testFailed: failed
解决方案进展
此前提交相关问题至JUnit官方仓库,暂未得到有效回复。后续收到官方提示,可尝试使用LifecycleMethodExecutionExceptionHandler处理该场景,相关内容会进一步更新。
内容的提问来源于stack exchange,提问作者Michael Fleytman
相关产品推荐
相关产品推荐

