测试

Maven Test

Maven 本身并不是一个单元测试框架,它只是在构建执行到特定生命周期阶段的时候,通过插件来执行 JUnit 或者 TestNG 的测试用例。这个插件就是 maven-surefire-plugin,也可以称为测试运行器(Test Runner),它能兼容 JUnit 3、JUnit 4 以及 TestNG。在默认情况下,maven-surefire-plugin 的 test 目标会自动执行测试源码路径(默认为 src/test/java/)下所有符合一组命名模式的测试类。这组模式为:

  • *Test_.java:任何子目录下所有命名以 Test 开关的 Java 类。
  • **Test.java:任何子目录下所有命名以 Test 结尾的 Java 类。
  • **TestCase.java:任何子目录下所有命名以 TestCase 结尾的 Java 类。

在 Java 世界中,由 Kent Beck 和 Erich Gamma 建立的 JUnit 是事实上的单元测试标准。要使用 JUnit,我们首先需要为 Hello World 项目添加一个 JUnit 依赖,修改项目的 POM 如代码清单。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.juvenxu.mvnbook</groupId>
  <artifactId>hello-world</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Hello World Project</name>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.7</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

代码中添加了 dependencies 元素,该元素下可以包含多个 dependency 元素以声明项目的依赖,这里我们添加了一个依赖——groupId 是 junit,artifactId 是 junit,version 是 4.7。前面我们提到 groupId、artifactId 和 version 是任何一个 Maven 项目最基本的坐标,JUnit 也不例外,有了这段声明,Maven 就能够自动下载 junit-4.7.jar。也许你会问,Maven 从哪里下载这个 jar 呢?在 Maven 之前,我们可以去 JUnit 的官网下载分发包。而现在有了 Maven,它会自动访问中央仓库(http://repo1.maven.org/maven2/) ,下载需要的文件。读者也可以自己访问该仓库,打开路径 junit/junit/4.7/,就能看到 junit-4.7.pom 和 junit-4.7.jar。

上述 POM 代码中还有一个值为 test 的元素 scope,scope 为依赖范围,若依赖范围为 test 则表示该依赖只对测试有效,换句话说,测试代码中的 import JUnit 代码是没有问题的,但是如果我们在主代码中用 import JUnit 代码,就会造成编译错误。如果不声明依赖范围,那么默认值就是 compile,表示该依赖对主代码和测试代码都有效。

配置了测试依赖,接着就可以编写测试类,回顾一下前面的 HelloWorld 类,现在我们要测试该类的 sayHello()方法,检查其返回值是否为“Hello Maven”。在 src/test/java 目录下创建文件,其内容如代码清单如下:

public class HelloWorldTest {

  @Test
  public void testSayHello() {
    HelloWorld helloWorld = new HelloWorld();

    String result = helloWorld.sayHello();

    assertEquals("Hello Maven", result);
  }
}

测试用例编写完毕之后就可以调用 Maven 执行测试,运行 mvn clean test。构建在执行 compiler:testCompile 任务的时候失败了,Maven 输出提示我们需要使用-source 5 或更高版本以启动注释,也就是代码中 JUnit 4 的@Test 注解。这是 Maven 初学者常常会遇到的一个问题。由于历史原因,Maven 的核心插件之一 compiler 插件默认只支持编译 Java 1.3,因此我们需要配置该插件使其支持 Java 5,见代码清单:

<project>
<build>
<plugins>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
       <source>1.5</source>
       <target>1.5</target>
     </configuration>
   </plugin>
</plugins>
</build>
</project>

该 POM 省略了除插件配置以外的其他部分。现在再执行 mvn clean test,结果正常。

测试命令

Maven 中使用 package、install 等命令时会自动调用 Test 组件,mvn package -DskipTests命令可以跳过测试。也可以在插件配置的时候设置跳过:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.5</version>
    <configuration>
        <skipTests>true</skipTests>
    </configuration>
</plugin>

maven-surefire-plugin 提供了一个 test 参数让 Maven 用户能够在命令行指定要运行的测试用例。如:

mvn test -Dtest=RandomGeneratorTest

也可以使用通配符:

mvn test -Dtest=Random*Test

或者也可以使用“,”号指定多个测试类:

mvn test -Dtest=Random*Test,AccountCaptchaServiceTest

如果由于历史原因,测试类不符合默认的三种命名模式,可以通过 pom.xml 设置 maven-surefire-plugin 插件添加命名模式或排除一些命名模式。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.5</version>
    <configuration>
        <includes>
            <include>**/*Tests.java</include>
        </includes>
        <excludes>
            <exclude>**/*ServiceTest.java</exclude>
            <exclude>**/TempDaoTest.java</exclude>
        </excludes>
    </configuration>
</plugin>

Coverage | 测试覆盖率

maven-surefire-plugin

如果你执行过 mvn test 或者执行其他 maven 命令时跑了测试用例,你就已经用过 maven-surefire-plugin 了。maven-surefire-plugin 是 maven 里执行测试用例的插件,不显示配置就会用默认配置。这个插件的 surefire:test 命令会默认绑定 maven 执行的 test 阶段。

配置 JUnit

插件自动匹配

最简单的配置方式就不配置或者是只声明插件。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.19</version>
</plugin>

这个时候 maven-surefire-plugin 会按照如下逻辑去寻找 JUnit 的版本并执行测试用例。

if the JUnit version in the project >= 4.7 and the parallel attribute has ANY value
    use junit47 provider
if JUnit >= 4.0 is present
    use junit4 provider
else
    use junit3.8.1

插件手动匹配

当然,如果你明确用的是 JUnit4.7 及以上版本,可以明确声明:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.19</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.maven.surefire</groupId>
            <artifactId>surefire-junit47</artifactId>
            <version>2.19</version>
        </dependency>
    </dependencies>
</plugin>

JUnit4.0(含)到 JUnit4.7(不含)的版本,这样声明:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.19</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.maven.surefire</groupId>
            <artifactId>surefire-junit4</artifactId>
            <version>2.19</version>
        </dependency>
    </dependencies>
</plugin>

JUnit3.8(含)到 JUnit4.0(不含)的版本,这样声明:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.19</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.maven.surefire</groupId>
            <artifactId>surefire-junit3</artifactId>
            <version>2.19</version>
        </dependency>
    </dependencies>
</plugin>

JUnit3.8 以下的版本 surefire 不支持。建议大家用最新的 JUnit 版本,目前是 4.12.

<dependencies>
    [...]
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    [...]
</dependencies>
下一页