2. 概述
本文将深入探讨如何使用自定义测试运行器(Test Runner)来执行 JUnit 测试。简单来说,要指定自定义运行器,我们需要使用 @RunWith
注解。
3. 准备工作
首先在 pom.xml
中添加标准的 JUnit 依赖:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
4. 实现自定义运行器
下面通过示例展示如何编写自定义 Runner
并通过 @RunWith
运行它。
JUnit 运行器本质是继承自 JUnit 抽象 Runner
类的子类,负责通过反射机制执行 JUnit 测试。
以下是 Runner
抽象方法的实现:
public class TestRunner extends Runner {
private Class testClass;
public TestRunner(Class testClass) {
super();
this.testClass = testClass;
}
@Override
public Description getDescription() {
return Description
.createTestDescription(testClass, "My runner description");
}
@Override
public void run(RunNotifier notifier) {
System.out.println("running the tests from MyRunner: " + testClass);
try {
Object testObject = testClass.newInstance();
for (Method method : testClass.getMethods()) {
if (method.isAnnotationPresent(Test.class)) {
notifier.fireTestStarted(Description
.createTestDescription(testClass, method.getName()));
method.invoke(testObject);
notifier.fireTestFinished(Description
.createTestDescription(testClass, method.getName()));
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
关键点解析:
getDescription
方法继承自Describable
,返回包含测试信息的Description
对象run
方法通过反射调用目标测试方法- 构造函数必须接收
Class
参数(JUnit 规范要求) RunNotifier
用于触发测试进度事件
在测试类中使用该运行器:
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
@RunWith(TestRunner.class)
public class CalculatorTest {
Calculator calculator = new Calculator();
@Test
public void testAddition() {
System.out.println("in testAddition");
assertEquals("addition", 8, calculator.add(5, 3));
}
}
执行结果:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.baeldung.junit.CalculatorTest
running the tests from MyRunner: class com.baeldung.junit.CalculatorTest
in testAddition
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
5. 专业运行器扩展
相比直接继承底层的 Runner
类,**更推荐继承其专业子类:ParentRunner
或 BlockJUnit4ClassRunner
**。
✅ ParentRunner
:以层级方式执行测试
✅ BlockJUnit4ClassRunner
:具体实现类,适合覆盖特定方法
示例扩展 BlockJUnit4ClassRunner
:
public class BlockingTestRunner extends BlockJUnit4ClassRunner {
public BlockingTestRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
protected Statement methodInvoker(FrameworkMethod method, Object test) {
System.out.println("invoking: " + method.getName());
return super.methodInvoker(method, test);
}
}
使用 @RunWith(JUnit4.class)
会调用当前版本的默认 JUnit 4 运行器:
@RunWith(JUnit4.class)
public class CalculatorTest {
Calculator calculator = new Calculator();
@Test
public void testAddition() {
assertEquals("addition", 8, calculator.add(5, 3));
}
}
6. 总结
JUnit 运行器具有高度可定制性,允许开发者:
- 修改测试执行流程
- 重构整个测试过程
⚠️ 踩坑提示:只需做少量修改时,优先查看 BlockJUnit4ClassRunner
的受保护方法
常用第三方运行器实现:
- SpringJUnit4ClassRunner
- MockitoJUnitRunner
- HierarchicalContextRunner
- Cucumber Runner
所有示例代码可在 GitHub 项目 中获取(Maven 项目,可直接导入运行)。