一、maven-surefire-plugin
在实际的项目开发中我们通常会对我们编写的代码进行测试。在这一篇中我们将详细介绍一下,如何使用Maven进行测试。在Maven中执行测试用例非常的简单,在之前介绍生命周期时我们知道,Maven可以通过插件的方式绑定其生命周期实现我们自定义的业务逻辑。Maven就是通过这样的方式,使用maven-surefire-plugin
插件方式实现在Maven中使用测试用例的。下面我们介绍一下该插件具体的规则:
**/Test*.java:任何子目录下所有命名以Test开头的Java类。
**/*Test.java:任何子目录下所有命名以Test结尾的Java类。
**/*TestCase.java:任何子目录下所有命名以TestCase结尾的Java类。
二、JUnit
只要将测试类按上述方式命名,Maven就能自动运行它们。但上述的插件只是能绑定相应的生命周期,实际上运行测试用例的功能是由测试框架实现的,也就是比较知名的JUnit
和TestNG
等。所以我们在Maven中在使用测试用例的时候,还需要配置上面的依赖信息才可以使用。具体配置如下:
- pom.xml
<?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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-mall</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
因为有关JUnit
的内容我们之前已经介绍过了,我们这里就不在进行代码演示了。当然我们也可以使用以下命令在项目构建的时候跳过测试用例的执行:
mvn package-DskipTests
上面中的package
为项目构建的名称。但上面的命令在执行的时候,每次都要编写确实比较麻烦,所以Maven还可以通过配置的方式指定项目构建的时候执行哪些测试用例。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
同样的我们也可以使用同样的方式在配置中忽略相关的测试用例:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<excludes>
<exclude>**/*ServiceTest.java</exclude>
<exclude>**/TempDaoTest.java</exclude>
</excludes>
</configuration>
</plugin>
当然我也可以通过命令的方式指定我们想要执行的测试用例。
mvn test-Dtest=MazheMavenMallTest
也可以同时执行多个测试用例,多个测试用例使用逗号分割。
mvn test-Dtest=MazheMavenMallTest,MazheMavenOrderTest
也可以通过星号匹配多个测试用例。
mvn test-Dtest=MazheMaven*Test
三、cobertura-maven-plugin
maven-surefire-plugin插件默认会帮我们生成测试用例的报告。有两种格式,一种是简单的文本报告,一种是xml形式的报告。当我们执行测试用例后,就会自动将上述的报告生成到target/surefire-reports
目录下。下面我们演示一下。同样的我们还是以mazhe-maven-mall
项目为例。由于使用测试需要使用junit
依赖。,所以我们需要在mazhe-maven-mall
项目中添加junit
依赖。
- pom.xml(mazhe-maven-mall)
<?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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-mall</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- MazheMavenMallTest
import org.junit.Test;
public class MazheMavenMallTest {
@Test
public void test() {
System.out.println("Hello World Mazhe Maven Mall Test!");
}
}
下面我们执行一下上面的测试用例。通常我们只需要在IDEA中通过右键执行即可,但这次我们使用一下上面的命令试一下。
mvn test -Dtest=MazheMavenMallTest
- 日志
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running MazheMavenMallTest
Hello World Mazhe Maven Mall Test!
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.075 s -- in MazheMavenMallTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.160 s
[INFO] Finished at: 2023-08-26T11:23:20+08:00
[INFO] ------------------------------------------------------------------------
下面我们查看一下项目中的target/surefire-reports
目录是否生成了测试报告。
我们看上图显示,成功的生了项目的测试报告了,并且同时生成了两种格式。下面我们查看一下里面的内容。
- MazheMavenMallTest.txt
-------------------------------------------------------------------------------
Test set: MazheMavenMallTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.075 s -- in MazheMavenMallTest
- TEST-MazheMavenMallTest.xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report-3.0.xsd" version="3.0" name="MazheMavenMallTest" time="0.075" tests="1" errors="0" skipped="0" failures="0">
<properties>
<property name="gopherProxySet" value="false"/>
<property name="awt.toolkit" value="sun.lwawt.macosx.LWCToolkit"/>
<property name="file.encoding.pkg" value="sun.io"/>
<property name="java.specification.version" value="1.8"/>
<property name="sun.cpu.isalist" value=""/>
<property name="sun.jnu.encoding" value="UTF-8"/>
<property name="java.class.path" value="/Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall/target/test-classes:/Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall/target/classes:/Users/md/.m2/repository/junit/junit/4.12/junit-4.12.jar:/Users/md/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:"/>
<property name="java.vm.vendor" value="Oracle Corporation"/>
<property name="sun.arch.data.model" value="64"/>
<property name="java.vendor.url" value="http://java.oracle.com/"/>
<property name="user.timezone" value=""/>
<property name="java.vm.specification.version" value="1.8"/>
<property name="os.name" value="Mac OS X"/>
<property name="user.country" value="CN"/>
<property name="sun.java.launcher" value="SUN_STANDARD"/>
<property name="sun.boot.library.path" value="/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib"/>
<property name="sun.java.command" value="/Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall/target/surefire/surefirebooter-20230826112320490_3.jar /Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall/target/surefire 2023-08-26T11-23-20_362-jvmRun1 surefire-20230826112320490_1tmp surefire_0-20230826112320490_2tmp"/>
<property name="http.nonProxyHosts" value="local|*.local|169.254/16|*.169.254/16"/>
<property name="test" value="MazheMavenMallTest"/>
<property name="surefire.test.class.path" value="/Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall/target/test-classes:/Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall/target/classes:/Users/md/.m2/repository/junit/junit/4.12/junit-4.12.jar:/Users/md/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:"/>
<property name="sun.cpu.endian" value="little"/>
<property name="user.home" value="/Users/md"/>
<property name="user.language" value="zh"/>
<property name="java.specification.vendor" value="Oracle Corporation"/>
<property name="java.home" value="/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre"/>
<property name="basedir" value="/Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall"/>
<property name="file.separator" value="/"/>
<property name="line.separator" value="
"/>
<property name="java.vm.specification.vendor" value="Oracle Corporation"/>
<property name="java.specification.name" value="Java Platform API Specification"/>
<property name="java.awt.graphicsenv" value="sun.awt.CGraphicsEnvironment"/>
<property name="surefire.real.class.path" value="/Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall/target/surefire/surefirebooter-20230826112320490_3.jar"/>
<property name="sun.boot.class.path" value="/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/classes"/>
<property name="sun.management.compiler" value="HotSpot 64-Bit Tiered Compilers"/>
<property name="ftp.nonProxyHosts" value="local|*.local|169.254/16|*.169.254/16"/>
<property name="java.runtime.version" value="1.8.0_371-b11"/>
<property name="user.name" value="md"/>
<property name="path.separator" value=":"/>
<property name="os.version" value="13.4.1"/>
<property name="java.endorsed.dirs" value="/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib/endorsed"/>
<property name="java.runtime.name" value="Java(TM) SE Runtime Environment"/>
<property name="file.encoding" value="UTF-8"/>
<property name="java.vm.name" value="Java HotSpot(TM) 64-Bit Server VM"/>
<property name="localRepository" value="/Users/md/.m2/repository"/>
<property name="java.vendor.url.bug" value="http://bugreport.sun.com/bugreport/"/>
<property name="java.io.tmpdir" value="/var/folders/4h/rgmf1__n4fxfn7c23nn65fkw0000gn/T/"/>
<property name="java.version" value="1.8.0_371"/>
<property name="user.dir" value="/Users/md/Desktop/midai-mazhe-maven/mazhe-maven-mall"/>
<property name="os.arch" value="x86_64"/>
<property name="java.vm.specification.name" value="Java Virtual Machine Specification"/>
<property name="java.awt.printerjob" value="sun.lwawt.macosx.CPrinterJob"/>
<property name="sun.os.patch.level" value="unknown"/>
<property name="java.library.path" value="/Users/md/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:."/>
<property name="java.vm.info" value="mixed mode"/>
<property name="java.vendor" value="Oracle Corporation"/>
<property name="java.vm.version" value="25.371-b11"/>
<property name="java.specification.maintenance.version" value="4"/>
<property name="java.ext.dirs" value="/Users/md/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java"/>
<property name="sun.io.unicode.encoding" value="UnicodeBig"/>
<property name="java.class.version" value="52.0"/>
<property name="socksNonProxyHosts" value="local|*.local|169.254/16|*.169.254/16"/>
</properties>
<testcase name="test" classname="MazheMavenMallTest" time="0.008">
<system-out><![CDATA[Hello World Mazhe Maven Mall Test!
]]></system-out>
</testcase>
</testsuite>
上面的内容虽然可以显示测试报告的信息,但是不太方便我们查看。所以为了我们更直观查看以及统计测试覆盖率,我们可以引入cobertura-maven-plugin
插件来实现上面的功能。具体配置如下:
- pom.xml(mazhe-maven-mall)
<?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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>midai-mazhe-maven</artifactId>
<groupId>cn.ma-zhe</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mazhe-maven-mall</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
然后我们执行以下命令来生成测试报告的覆盖率:
mvn cobertura:cobertura
- 日志
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.071 s -- in MazheMavenMallTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] <<< cobertura:2.7:cobertura (default-cli) < [cobertura]test @ mazhe-maven-mall <<<
[INFO]
[INFO]
[INFO] --- cobertura:2.7:cobertura (default-cli) @ mazhe-maven-mall ---
[INFO] Cobertura 2.1.1 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
[INFO] Cobertura: Loaded information on 1 classes.
Report time: 167ms
[INFO] Cobertura Report generation was successful.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.804 s
[INFO] Finished at: 2023-08-26T12:20:08+08:00
[INFO] ------------------------------------------------------------------------
然后我们查看一下项目的中target/site
目录。因为cobertura-maven-plugin
插件会将生成的测试报告文件存放到上述的目录中。
然后我们打开项目中的index.html
文件。因为是html
文件,所以我们可以通过浏览器打开。
通过浏览器查看我们就可以很直观的查看测试覆盖率的情况。并且还可以查看到具体的测试用例的代码。
下面我们创建一个新类添加几个方法来更方便的我们观察上面的测试覆盖率。
- MazheMavenMall
public class MazheMavenMall {
public void mall() {
System.out.println("Hello World Mazhe Maven mall!");
}
public void order() {
System.out.println("Hello World Mazhe Maven order!");
}
public void user() {
System.out.println("Hello World Mazhe Maven user!");
}
}
- MazheMavenMallTest
import org.junit.Test;
public class MazheMavenMallTest {
@Test
public void mall() {
MazheMavenMall mazheMavenMall = new MazheMavenMall();
mazheMavenMall.mall();
}
}
然后我们再次执行mvn cobertura:cobertura
命令。来观察一下测试覆盖率。
然后我们点击上面的类就可以查看里面测试的信息。
上图中前面的数字则表示执行了几次测试。下面我们在次执行一下mvn cobertura:cobertura
命令。来看一下类前面的数字会不会变。
我们看上图所示,类前面数字已经变成2了。因为我们已经执行了2次了。下面我们在修改一下测试用例里的代码添加order
方法。然后在测试一下。
- MazheMavenMallTest
import org.junit.Test;
public class MazheMavenMallTest {
@Test
public void mall() {
MazheMavenMall mazheMavenMall = new MazheMavenMall();
mazheMavenMall.mall();
}
@Test
public void order() {
MazheMavenMall mazheMavenMall = new MazheMavenMall();
mazheMavenMall.order();
}
}
下面我们在执行一下mvn cobertura:cobertura
命令来查看一下测试统计率。
这次我们order
方法前面的数字就变成1了。有一点这里要注意,这个测试的统计率,实际上是调用这个方法的次数。如果我们在上面mall
方法中调用了其它的方法,例如user
方法,那么在调用mall
方法时user
方法也会统计,例如下面的代码:
- MazheMavenMall
public class MazheMavenMall {
public void mall() {
System.out.println("Hello World Mazhe Maven mall!");
user();
}
public void order() {
System.out.println("Hello World Mazhe Maven order!");
}
public void user() {
System.out.println("Hello World Mazhe Maven user!");
}
}
下面我们再次调用mvn cobertura:cobertura
命令,查看一下统计率。
就是cobertura-maven-plugin
插件的功能。