17.6 测试Maven插件

编写Maven插件的最后一步是对其进行测试,单元测试较之于一般的Maven项目无异,可以参考第10章。手动测试Maven插件也是一种做法,读者可以将插件安装到本地仓库后,再找个项目测试该插件。本节要介绍的并非上述两种读者已经十分熟悉的测试方法,而是如何编写自动化的集成测试代码来验证Maven插件的行为。

读者可以想象一下,既然是集成测试,那么就一定需要一个实际的Maven项目,配置该项目使用插件,然后在该项目上运行Maven构建,最后再验证该构建成功与否,可能还需要检查构建的输出。

既然有数以千计的Maven插件,那么很可能已经有很多人遇到过上述的需求,因此Maven社区有一个用来帮助插件集成测试的插件,它就是maven-invoker-plugin。该插件能够用来在一组项目上执行Maven,并检查每个项目的构建是否成功,最后,它还可以执行BeanShell或者Groovy脚本来验证项目构建的输出。

BeanShell和Groovy都是基于JVM平台的脚本语言,读者可以访问http://www.bean-shell.org/和http://groovy.codehaus.org/以了解更多的信息。本章下面的内容会用到少许的Groovy代码,不过这些代码十分简单,很容易理解。

回顾一下前面的代码行统计插件,可以使用Archetype创建一个最简单的Maven项目,然后在该项目中配置maven-loc-plugin。如果一切正常,就应该能够看到如下的Maven构建输出:


[INFO]\src\main\java:13 lines of code in 1 files

[INFO]\src\test\java:38 lines of code in 1 files


为了验证这一行为,先配置maven-loc-plugin的POM使用maven-invoker-plugin,如代码清单17-6所示。

代码清单17-6 配置maven-Ioc-plugin使用maven-invoker-plugin


<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-invoker-plugin</artifactId>

<version>1.5</version>

<configuration>

<projectsDirectory>src/it</projectsDirectory>

<goals>

<goal>install</goal>

</goals>

<postBuildHookScript>validate.groovy</postBuildHookScript>

</configuration>

<executions>

<execution>

<id>integration-test</id>

<goals>

<goal>install</goal>

<goal>run</goal>

</goals>

</execution>

</executions>

</plugin>


代码清单17-6中maven-invoker-plugin有三项配置。首先projectDirectory用来配置测试项目的目录,也就是说在src/it目录下存放要测试的Maven项目源码;其次goals表示在测试项目上要运行的Maven目标,这里的配置就表示maven-invoker-plugin会在src/it目录下的各个Maven项目中运行mvn install命令;最后的postBuildHookScript表示在测试完成后要运行的验证脚本,这里是一个groovy文件。

从代码清单17-6中我们还看到,maven-invoker-plugin的两个目标install和run被绑定到了integration-test生命周期阶段。这里的install目标用来将当前的插件构建并安装到仓库中供测试项目使用,run目标则会执行定义好的mvn命令并运行验证脚本。

当然仅仅该配置还不够,src/it目录下必须有一个或者多个供测试的Maven项目,我们可以使用maven-archetype-quickstart创建一个项目并修改POM使用mvn-loc-plugin,如代码清单17-7所示。该测试项目的其余代码不再赘述。

代码清单17-7 maven-Ioc-plugin的测试项目POM


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

<artifactId>app</artifactId>

<packaging>jar</packaging>

<version>1.0-SNAPSHOT</version>

<name>app</name>

<url>http://maven.apache.org</url>

<dependencies>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>3.8.1</version>

<scope>test</scope>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>com.juvenxu.mvnbook</groupId>

<artifactId>maven-loc-plugin</artifactId>

<version>0.0.1-SNAPSHOT</version>

<executions>

<execution>

<goals>

<goal>count</goal>

</goals>

<phase>verify</phase>

</execution>

</executions>

</plugin>

</plugins>

</build>

</project>


代码清单17-7就是一个最简单的POM,然后配置maven-loc-plugin的count目标绑定到了verify生命周期阶段。

测试项目准备好了,现在要准备的是与该项目对应的验证脚本文件,即validate.groovy,它应该位于src/it/app目录下(即上述测试项目的根目录),内容如代码清单17-8所示。

代码清单17-8 maven-Ioc-plugin的集成测试验证脚本


def file=new File(basedir,'build.log')

def countMain=false

def countTest=false

file.eachLine{

if(it=~/src.main.java:13 lines of code in 1 files/)

countMain=true

if(it=~/src.test.java:38 lines of code in 1 files/)

countTest=true

}

if(!countMain)

throw new RuntimeException("incorrect src/main/java count info");

if(!countTest)

throw new RuntimeException("incorrect src/test/java count info");


这段Groovy代码做的事情很简单。它首先读取app项目目录下的build.log文件,当maven-invoker-plugin构建测试项目的时候,会把mvn输出保存到项目下的build.log文件中。因此,可以解析该日志文件来验证maven-loc-plugin是否输出了正确的代码行信息。

上述Groovy代码首先假设没有找到正确的主代码统计信息和测试代码统计信息,然后它逐行遍历日志文件,紧接着使用正则表达式检查寻找要检查的内容(两个斜杠//中间的内容是正则表达式,而=~表示寻找该正则表达式匹配的内容),如果找到期望的输出,就将countMain和countTest置为true。最后,如果这两个变量的值有false,就抛出对应的异常信息。

Maven会首先在测试项目app上运行mvn install命令,如果运行成功,则再执行vali-date.groovy脚本。只有脚本运行通过且没有异常,集成测试才算成功。

现在在maven-loc-plugin下运行mvn clean install,就能看到如下的输出:


[INFO] --- maven - invoker-plugin:1.5:install (integration-test) @ maven-locplugin

---

[INFO] Installing D:\ws-maven-book\maven-loc-plugin\pom.xml to D:\java\repository

\ com \ juvenxu \ mvnbook \ maven-loc-plugin \0.0.1-SNAPSHOT \ maven- loc- plugin-

0.0.1-SNAPSHOT.pom

[INFO] Installing D:\ws-maven-book \maven-loc-plugin \target \maven-loc-plugin-

0.0.1-SNAPSHOT.jar to D:\java \repository \com \juvenxu \mvnbook \maven-loc-plugin \

0.0.1-SNAPSHOT\maven-loc-plugin-0.0.1-SNAPSHOT.jar

[INFO]

[INFO] ---maven-invoker-plugin:1.5:run (integration-test) @ maven-loc-plugin ---

[WARNING] Filtering of parent/child POMs is not supported without cloning the projects

[INFO] Building: app\pom.xml

[INFO] ..SUCCESS (3.4 s)

[INFO] -------------------------------------------------

[INFO] Build Summary:

[INFO] Passed: 1, Failed: 0, Errors: 0, Skipped: 0

[INFO] -------------------------------------------------


从输出中可以看到maven-invoker-plugin的install目标将当前项目maven-loc-plugin安装至本地仓库,然后它的run目标构建测试项目app,并最后报告运行结果。

至此,所有Maven插件集成测试的步骤就都完成了。

上述样例只涉及了maven-invoker-plugin的很少一部分配置点,用户还可以配置:

debug(boolean):是否在构建测试项目的时候开启debug输出。

settingsFile(File):执行集成测试所使用的settings.xml,默认为本机环境settings.xml。

localRepositoryPath(File):执行集成测试所使用的本地仓库,默认就是本机环境仓库。

preBuildHookScript(String):构建测试项目之前运行的BeanShell或Groovy脚本。

postBuildHookScript(String):构建测试项目之后运行的BeanShell或Groovy脚本。

要了解更多的配置点,或者查看更多的样例。读者可以访问maven-invoker-plugin的站点:http://maven.apache.org/plugins/maven-invoker-plugin/。