Custom JUnit 4 Test Runners – 自定义JUnit 4测试运行器

最后修改: 2017年 10月 5日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick article, we’re going to focus on how to run JUnit tests using custom test runners.

在这篇快速文章中,我们将重点讨论如何使用自定义测试运行器来运行JUnit测试。

Simply put, in order to specify the custom runner, we’ll need to use the @RunWith annotation.

简单地说,为了指定自定义运行器,我们需要使用@RunWith 注解。

2. Preparation

2.准备

Let’s start by adding the standard JUnit dependency into our pom.xml:

让我们先把标准的JUnit依赖性加入我们的pom.xml

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>  
</dependency>

3. Implementing a Custom Runner

3.实现自定义运行器

In the following example, we’ll show how to write our own custom Runner – and run it using @RunWith.

在下面的例子中,我们将展示如何编写我们自己的自定义Runner – 并使用@RunWith运行它。

A JUnit Runner is a class that extends JUnit’s abstract Runner class and it is responsible for running JUnit tests, typically using reflection.

JUnit Runner是一个扩展了JUnit的抽象Runner类的类,它负责运行JUnit测试,通常使用反射。

Here, we’re implementing abstract methods of Runner class:

这里,我们要实现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);
        }
    }
}

The getDescription method is inherited from Describable and returns a Description that contains the information that is later being exported and may be used by various tools.

getDescription方法继承自Describable,并返回一个Description,该方法包含后来被导出的信息,可能被各种工具使用。

In the run implementation, we’re invoking the target test methods using reflection.

run实现中,我们正在使用反射来调用目标测试方法。

We’ve defined a constructor that takes a Class argument; this is a JUnit’s requirement. At runtime, JUnit will pass the target test class to this constructor.

我们定义了一个构造函数,它需要一个Class参数;这是JUnit的要求。在运行时,JUnit将把目标测试类传递给这个构造函数。

RunNotifier is used for firing events that have information about the test progress.

RunNotifier用于触发具有测试进度信息的事件。

Let’s use the runner in our test class:

让我们在我们的测试类中使用这个运行器。

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() {
        Syste.out.println("in testAddition");
        assertEquals("addition", 8, calculator.add(5, 3));
    }
}

The result we get:

我们得到的结果是。

-------------------------------------------------------
 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

4. Specialized Runners

4.专门的跑步者

Instead of extending the low-level Runner class, as we did in the last example, we can extend one of the specialized subclasses of Runner: ParentRunner or BlockJUnit4Runner.

与其像上一个例子中那样扩展低级别的Runner类,我们可以扩展Runner的一个专门的子类。ParentRunnerBlockJUnit4Runner

The abstract ParentRunner class runs the tests in a hierarchical manner.

抽象的ParentRunner类以分层的方式运行测试。

BlockJUnit4Runner is a concrete class and if we prefer to customize certain methods, we’ll probably be extending this class.

BlockJUnit4Runner是一个具体的类,如果我们喜欢定制某些方法,我们可能会扩展这个类。

Let’s see that with an example:

让我们通过一个例子来看看。

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);
    }
}

Annotating a class with @RunWith(JUnit4.class) will always invoke the default JUnit 4 runner in the current version of JUnit; this class aliases the current default JUnit 4 class runner:

@RunWith(JUnit4.class)来注释一个类,将总是调用当前版本的JUnit中默认的JUnit 4运行器;这个类是当前默认的JUnit 4类运行器的别名。

@RunWith(JUnit4.class)
public class CalculatorTest {
    Calculator calculator = new Calculator();

    @Test
    public void testAddition() {
        assertEquals("addition", 8, calculator.add(5, 3));
    }
}

5. Conclusion

5.结论

JUnit Runners are highly adaptable and let the developer change the test execution procedure and the whole test process.

JUnit Runners具有高度的适应性,让开发者改变测试执行程序和整个测试过程。

If we only want to make minor changes it is a good idea to have a look at the protected methods of BlockJUnit4Class runner.

如果我们只想做一些小的改动,最好看看BlockJUnit4Class runner的保护方法。

Some popular third-party implementations of runners for use include SpringJUnit4ClassRunner, MockitoJUnitRunner, HierarchicalContextRunner, Cucumber Runner and much more.

一些流行的第三方实现的运行器的使用包括SpringJUnit4ClassRunner、MockitoJUnitRunner、HierarchicalContextRunner、Cucumber Runner等等。

The implementation of all these examples and code snippets can be found in the GitHub project – this is a Maven project, so it should be easy to import and run as it is.

所有这些例子和代码片段的实现都可以在GitHub项目中找到–这是一个Maven项目,所以应该很容易导入并按原样运行。