如何在JUnit 5测试套件中仅运行指定测试方法?
JUnit 5测试套件筛选特定测试方法的方案
一、基础筛选方式:利用套件注解直接过滤
如果目标方法有统一命名规则(比如所有第一个方法都叫testFirst()),可以直接用JUnit Platform Suite提供的@IncludeMethodPatterns注解,无需自定义扩展:
import org.junit.platform.suite.api.IncludeMethodPatterns; import org.junit.platform.suite.api.SelectClasses; import org.junit.platform.suite.api.Suite; import org.junit.platform.suite.api.SuiteDisplayName; @SelectClasses({com.example.junit5testexample.A.class, com.example.junit5testexample.B.class}) @Suite @SuiteDisplayName("junit5 suite") // 匹配所有类中方法名符合正则的测试方法,示例为匹配以testFirst开头的方法 @IncludeMethodPatterns("testFirst.*") public class JUnit5TestSuiteExample { }
若需要排除特定方法,可搭配@ExcludeMethodPatterns注解使用。
二、针对“运行每个类的第一个测试方法”的定制需求
如果方法名无统一规律,仅需执行每个测试类中定义的第一个测试方法,需通过自定义扩展实现,推荐两种方案:
方案1:自定义DiscoveryFilter(测试发现阶段过滤)
DiscoveryFilter可在JUnit扫描测试类时直接过滤不符合条件的方法,只保留每个类的第一个测试方法,效率更高:
- 实现
MethodDiscoveryFilter接口:
import org.junit.platform.commons.support.AnnotationSupport; import org.junit.platform.engine.discovery.MethodDiscoveryFilter; import org.junit.platform.engine.discovery.MethodSelector; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class FirstMethodPerClassFilter implements MethodDiscoveryFilter { private final Map<Class<?>, Boolean> classProcessed = new HashMap<>(); @Override public boolean apply(MethodSelector selector) { Method method = selector.getJavaMethod(); Class<?> testClass = method.getDeclaringClass(); // 该类已保留第一个测试方法,直接过滤 if (classProcessed.containsKey(testClass)) { return false; } // 确认当前方法是@Test注解标记的测试方法 boolean isTestMethod = AnnotationSupport.isAnnotated(method, org.junit.jupiter.api.Test.class); if (isTestMethod) { classProcessed.put(testClass, true); return true; } return false; } }
- 在测试套件中注册过滤器:
import org.junit.platform.suite.api.SelectClasses; import org.junit.platform.suite.api.Suite; import org.junit.platform.suite.api.SuiteDisplayName; import org.junit.platform.suite.api.ConfigurationParameter; @SelectClasses({com.example.junit5testexample.A.class, com.example.junit5testexample.B.class}) @Suite @SuiteDisplayName("junit5 suite") // 注册自定义方法发现过滤器 @ConfigurationParameter( key = "junit.platform.discovery.method.filters", value = "com.example.junit5testexample.FirstMethodPerClassFilter" ) public class JUnit5TestSuiteExample { }
方案2:自定义TestExecutionCondition(测试执行阶段过滤)
这种方式会先让JUnit发现所有测试方法,再在执行前判断是否运行,适合需动态决策的场景:
- 实现
ExecutionCondition接口:
import org.junit.jupiter.api.extension.ConditionEvaluationResult; import org.junit.jupiter.api.extension.ExecutionCondition; import org.junit.jupiter.api.extension.ExtensionContext; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class FirstMethodPerClassCondition implements ExecutionCondition { @Override public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { Method currentMethod = context.getRequiredTestMethod(); Class<?> testClass = currentMethod.getDeclaringClass(); // 收集该类所有带@Test注解的方法 List<Method> testMethods = new ArrayList<>(); for (Method method : testClass.getDeclaredMethods()) { if (method.isAnnotationPresent(org.junit.jupiter.api.Test.class)) { testMethods.add(method); } } // 判断当前方法是否为第一个测试方法 if (testMethods.indexOf(currentMethod) == 0) { return ConditionEvaluationResult.enabled("运行该类的第一个测试方法"); } else { return ConditionEvaluationResult.disabled("跳过非第一个测试方法"); } } }
- 在测试套件中用
@ExtendWith注册扩展:
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.platform.suite.api.SelectClasses; import org.junit.platform.suite.api.Suite; import org.junit.platform.suite.api.SuiteDisplayName; @SelectClasses({com.example.junit5testexample.A.class, com.example.junit5testexample.B.class}) @Suite @SuiteDisplayName("junit5 suite") @ExtendWith(FirstMethodPerClassCondition.class) public class JUnit5TestSuiteExample { }
三、Extensions使用建议
- 若仅需按命名规则过滤方法,优先用JUnit Suite自带的
@IncludeMethodPatterns,无需自定义扩展; - 若需基于类中方法顺序这类定制逻辑,再使用Extensions。其中DiscoveryFilter更高效,因为它在扫描阶段就完成过滤,避免后续无效的执行准备工作;ExecutionCondition则适合需要动态判断是否执行的场景。
内容的提问来源于stack exchange,提问作者zaoras
相关产品推荐
相关产品推荐

