maven使用

作用

自动构建、依赖管理、项目信息管理

maven坐标

groupId
当前Maven项目隶属的实际项目,表示方式与Java包名的表示方式类似。
artifactId
定义实际项目中的一个Maven项目,推荐做法是使用实际项目名称作为artifact的前缀。
version
定义Maven项目当前的版本。
packaging
定义元素的打包方式。打包方式与生成的文件扩展名对应。打包方式影响到构建的生命周期。
classifier
定义构件输出的一些附属构件。例如***-javadoc.jar、***-sources.jar

依赖范围

maven的3种classpath分别用于编译、测试和执行。
scope控制依赖作用于哪个classpath,如下图:
在这里插入图片描述

仓库的布局

任何一个构件都有其唯一的坐标,根据这个坐标可以定义其在仓库中的唯一存储路径,这便是maven的仓库布局方式。
坐标与路径的关系
groupId/artifactId/version/artifactId-version.packaging

仓库分类

本地仓库
settings.xml文件中的localRepository标签可以配置本地仓库目录。
构件只有在本地仓库中才能有Maven项目使用,构件进入到本地仓库的方式有两种:1)从远程仓库中下载;2)将本地项目的构件安装到本地仓库中。
中央仓库
中央仓库是一个默认的远程仓库,maven的安装文件自带了中央仓库的配置。使用解压工具打开jar文件$M2_HOME/lib/maven-model-builder.jar,然后访问路径org/apache/maven/model/pom-4.0.0.xml。可以看到如下配置:

  <repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

包含这段配置的文件是所有maven项目都会继承的超级POM。
私服
一种特殊的远程仓库,架设在局域网内,代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件时,它从私服请求,如果私服不存在该构件,则从外部的远程仓库下载,缓存在私服中后,在位Maven的下载请求提供服务。一些无法从外部仓库下载到的构件也能从本地上传到私服供大家使用。
在这里插入图片描述

生命周期和插件

Maven生命周期就是为了对所有的构建过程进行抽象和统一,这个生命周期包括项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤。但生命周期是抽象的,实际的任务都交由插件完成。每个构建步骤都可以绑定一个或多个插件行为,Maven为大多数构建步骤编写并绑定了默认插件。
Maven拥有三套相互独立的生命周期,分别为clean、default和site。clean生命周期的目的是清理项目,default生命周期的目的是构建项目,site生命周期的目的是建立项目站点。
Maven的核心仅仅定义了抽象的生命周期,具体的任务是交由插件完成的,插件以独立的构件形式存在,因此Maven核心的分发包只有不到3MB大小,Maven会在需要的时候下载并使用插件。每个插件具有多个功能,每个功能就是一个插件目标。

生命周期

clean生命周期

pre-clean
clean
post-clean

default生命周期

validate
initialize
generate-sources
process-sources
generate-resources
process-resources
compile
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources
test-compile
process-test-classes
test
prepare-package
package
pre-integration-test
integration-test
post-integration-test
verify
install
deploy

site生命周期

pre-site
site
post-site
site-deploy

插件

Maven is - at its heart - a plugin execution framework.There are the build and the reporting plugins:

  • Build plugins will be executed during the build and they should be configured in the element from the POM.
  • Reporting plugins will be executed during the site generation and they should be configured in the <reporting/> element from the POM. Because the result of a Reporting plugin is part of the generated site, Reporting plugins should be both internationalized and localized. You can read more about the localization of our plugins and how you can help.

Clean生命周期阶段与插件目标的绑定关系

在这里插入图片描述
Site生命周期阶段与插件目标的绑定关系:
在这里插入图片描述
Default生命周期的阶段与插件目标的绑定关系由项目打包类型决定,打包类型是通过POM中的packaging元素定义的。基于jar打包类型的项目生命周期阶段与插件目标的绑定关系如下:
在这里插入图片描述

自定义绑定

除了内置绑定以外,用户还能够自己选择将某个插件目标绑定到生命周期的某个阶段上,这种自定义绑定方式能让Maven项目在构建过程中执行更多更富特色的任务。
一个常见的例子是创建项目的源码jar包,内置的插件绑定关系中并没有设计这一任务,因此需要用户自行配置。maven-souce-plugin插件的jar-no-fork目标可以完成该任务,将其绑定到default生命周期的verify阶段上,在执行完集成测试后和安装构件之前创建源码jar包。配置如下:

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-source-plugin</artifactId>
			<version>2.1.1</version>
			<executions>
				<execution>
					<id>attach-sources</id>
					<phase>verify</phase>
					<goals>
						<goal>jar-no-fork</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
   </build>

当多个插件目标绑定到同一个阶段的时候,这些插件声明的先后顺序决定了目标的执行顺序。

插件配置

用户可以配置插件目标的参数,进一步调整目标所执行的任务,以满足项目需求。用户可以通过命令行和POM配置等方式来配置这些参数。

命令行插件配置

用户可以在Maven命令中使用-D参数,并伴随一个参数键=参数值的形式,来配置插件目标的参数。
例如mvn install -Dmaven.test.skip = true,可以跳过执行测试。

POM中插件全局配置

<plugin>  
    <groupId>org.apache.maven.plugins</groupId>  
    <artifactId>maven-compiler-plugin</artifactId>  
    <configuration>  
        <source>1.6</source>  
        <target>1.6</target>  
        <encoding>utf-8</encoding>  
    </configuration>  
</plugin> 

POM中插件任务配置

<build>  
    <plugins>  
        <plugin>  
            <groupId>org.apache.maven.plugins</groupId>  
            <artifactId>maven-antrun-plugin</artifactId>  
            <version>1.3</version>  
            <executions>  
                <execution>  
                    <id>ant-validate</id>  
                    <phase>validate</phase>  
                    <goals>  
                        <goal>run</goal>  
                    </goals>  
                    <configuraction>  
                        <tasks>  
                            <echo>I'm bound to validate phase.</echo>  
                        </tasks>  
                    </configuraction>  
                </execution>  
                <execution>  
                    <id>ant-verify</id>  
                    <phase>verify</phase>  
                    <goals>  
                        <goal>run</goal>  
                    </goals>  
                    <configuraction>  
                        <tasks>  
                            <echo>I'm bound to verify phase.</echo>  
                        </tasks>  
                    </configuraction>  
                </execution>  
            </executions>  
        </plugin>  
    </plugins>  
</build>

聚合与继承

maven应用到实际项目中的时候,需要将项目分成不同的模块。聚合特性能够把项目的各个模块聚合在一起构建,而继承特性能帮助抽取各模块相同的依赖和插件等配置,简化POM,促进各个模块配置的一致性。

聚合

聚合模块中的<modules></modules>配置了被聚合的模块,modules的值是相对当前pom的目录,打包类型为pom。
例子:
聚合模块的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.mvnbook.account</groupId>
	<artifactId>account-aggregator</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Account Aggregator</name>
	<modules>
		<module>account-email</module>
		<module>account-persist</module>
	</modules>
</project>

被聚合模块的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.mvnbook.account</groupId>
	<artifactId>account-email</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>Account Email</name>

	<properties>
		<javax.mail.version>1.4.1</javax.mail.version>
		<greenmail.version>1.3.1b</greenmail.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>2.5.6</version>		
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>2.5.6</version>				
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>2.5.6</version>				
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>2.5.6</version>				
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
		</dependency>
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>${javax.mail.version}</version>
		</dependency>		
		<dependency>
			<groupId>com.icegreen</groupId>
			<artifactId>greenmail</artifactId>
			<version>${greenmail.version}</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
	</build>
</project>
<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.account</groupId>
	<artifactId>account-persist</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>Account Persist</name>

  <properties>
  	<dom4j.version>1.6.1</dom4j.version>
  </properties>

	<dependencies>
		<dependency>
			<groupId>dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>${dom4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>2.5.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>2.5.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>2.5.6</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
		</dependency>
	</dependencies>

	<build>
		<testResources>
			<testResource>
				<directory>src/test/resources</directory>
				<filtering>true</filtering>
			</testResource>
		</testResources>
	</build>
</project>

继承

父pom文件的打包类型为pom,子pom文件中添加<parent></parent>,<relativePath>值为父pom文件的相对路径。
反应堆:在一个多模块的Maven项目中,反应堆是指所有模块组成的一个构建结构。
例子:
父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.mvnbook.account</groupId>
	<artifactId>account-parent</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Account Parent</name>
	<properties>
		<springframework.version>2.5.6</springframework.version>
		<junit.version>4.7</junit.version>
	</properties>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-beans</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context-support</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>${junit.version}</version>
				<scope>test</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<configuration>
						<source>1.5</source>
						<target>1.5</target>
					</configuration>
				</plugin>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-resources-plugin</artifactId>
					<configuration>
						<encoding>UTF-8</encoding>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>	
</project>

子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>
	
	<parent>
		<groupId>com.juvenxu.mvnbook.account</groupId>
		<artifactId>account-parent</artifactId>
		<version>1.0.0-SNAPSHOT</version>
		<relativePath>../account-parent/pom.xml</relativePath>
	</parent>
	
	<artifactId>account-email</artifactId>
	<name>Account Email</name>
	
	<properties>
		<javax.mail.version>1.4.1</javax.mail.version>
		<greenmail.version>1.3.1b</greenmail.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>			
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>			
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>			
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>${javax.mail.version}</version>
		</dependency>		
		<dependency>
			<groupId>com.icegreen</groupId>
			<artifactId>greenmail</artifactId>
			<version>${greenmail.version}</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
	</build>

</project>
<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>
	
	<parent>
		<groupId>com.juvenxu.mvnbook.account</groupId>
		<artifactId>account-parent</artifactId>
		<version>1.0.0-SNAPSHOT</version>
		<relativePath>../account-parent/pom.xml</relativePath>
	</parent>
	
	<artifactId>account-persist</artifactId>
	<name>Account Persist</name>

  <properties>
  	<dom4j.version>1.6.1</dom4j.version>
  </properties>

	<dependencies>
		<dependency>
			<groupId>dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>${dom4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
	</dependencies>

	<build>
		<testResources>
			<testResource>
				<directory>src/test/resources</directory>
				<filtering>true</filtering>
			</testResource>
		</testResources>
	</build>
</project>

将相同的配置信息提取到父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.mvnbook.account</groupId>
	<artifactId>account-parent</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Account Parent</name>
	<modules>
		<module>account-email</module>
		<module>account-persist</module>
	</modules>
	<properties>
		<springframework.version>2.5.6</springframework.version>
		<junit.version>4.7</junit.version>
	</properties>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-beans</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context-support</artifactId>
				<version>${springframework.version}</version>
			</dependency>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>${junit.version}</version>
				<scope>test</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<configuration>
						<source>1.5</source>
						<target>1.5</target>
					</configuration>
				</plugin>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-resources-plugin</artifactId>
					<configuration>
						<encoding>UTF-8</encoding>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>	
</project>

子模块pom文件的内容同上例。

Maven测试

Maven本身不是一个单元测试框架,Java世界中主流的单元测试框架为JUnit和TestNG,Maven所做的只是在构建执行到特定生命周期阶段的时候,通过插件来执行Junit或者TestNG的测试用例。这一插件就是maven-surefire-plugin,可以称之为测试运行器。test阶段与maven-surefire-plugin的test目标相绑定了,这是一个内置的绑定。
默认情况下,maven-surefire-plugin插件的test目标自动执行测试源码路径(src/test/java)下所有符合一组命名模式的测试类,这组模式为:
**/Test*.java,**/*Test.java,**/*TestCase.java

  • 跳过测试运行:mvn package-DskipTests,相当于禁用了maven-surefire-plugin:2.18.1:test,
  • 跳过测试编译和运行:mvn package-Dmaven.test.skip=true,相当于禁用了maven-surefire-plugin:2.18.1:test、maven-resources-plugin:2.6:testResources和maven-surefire-plugin:2.18.1:test。
  • 动态指定要运行的测试用例:mvn test -Dtest=测试用例类名
  • mvn test -Dmaven.test.failure.ignore=true 忽略单元测试失败

查看一个插件的详细信息

mvn help:describe -Dplugin=org.jacoco:jacoco-maven-plugin -Ddetail

命令行创建maven项目

mvn archetype:generate “-DgroupId=com.companyname.bank” “-DartifactId=consumerBanking” “-DarchetypeArtifactId=maven-archetype-quickstart” “-DinteractiveMode=false”

单元测试并行

从Junit4.7开始可以并行地运行单元测试。必须设置parallel参数,可以修改threadCount和useUnlimitedThreads属性。例如:

<plugins>
    [...]
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.0.0-M5</version>
        <configuration>
          <parallel>methods</parallel>
          <threadCount>10</threadCount>
        </configuration>
      </plugin>
    [...]
</plugins>

如果给parallel属性指定了任何值,并且你的工程使用了JUnit 4.7+,那么请求将被路由到并行JUnit provider,它使用了JUnit JUnitCore测试运行器。
这使得效率慢的单元测试可以有高的并行性,非常有用。
在Surefire 2.7中,使用并行的全部的选项不需要额外的依赖。在Surefire 2.16中,引进了新的thread-count属性,也就是threadCountSuites、hreadCountClasses和threadCountMethods。另外,新的属性parallelTestsTimeoutInSeconds和parallelTestsTimeoutForcedInSeconds被用于关闭并行执行,在过了一段时间,并且parallel属性指定了新的值。

Fork选项和并行测试执行

选择正确的fork策略和并行执行设置对内存需求和构建时间有重要影响。
Surefire插件提供了大量的并行执行单元测试的选项,允许你充分使用你的硬件。特别是fork有助于降低内存使用需求。
This page shall give you some ideas of how you can configure the test execution in a way best suitable for your environment.
本文将介绍怎样以一种最好的方式配置测试的执行。

并行测试执行

基本上,maven-surefire-plugin有两种方式达到并行测试执行的目的。
最显著的一种方法是使用parallel参数。可能的取值依赖于使用的test provider。对于JUnit4.7及以后,这可能是methods, classes, both, suites, suitesAndClasses, suitesAndMethods, classesAndMethods or all。作为单元测试的先决条件,JUnit运行器应当继承org.junit.runners.ParentRunner。如果没有通过@org.junit.runner.RunWith注解指定运行器,先决条件就会被完成。
对于maven-surefire-plugin:2.16,both取值过期了,但仍然可以使用,和classesAndMethods的作用相同。
并行机制的扩展通过使用下面的参数配置。useUnlimitedThreads 参数允许无限数量的线程。如果useUnlimitedThreads不为true,threadCount参数可以和可选的参数perCoreThreadCount=true一起使用。参数useUnlimitedThreads和threadCount能够在parallel参数取值的上线文中被说明。
As of maven-surefire-plugin:2.16, one can impose thread-count limitations on suites, classes or methods using one or more of the parameters threadCountSuites, threadCountClasses and threadCountMethods. If only threadCount is specified, maven-surefire-plugin attempts to optimize the thread counts for suites, classes and methods and reuses the threads in favor of a leaf, e.g. parallel methods (optionally increasing concurrent methods).
对于maven-surefire-plugin:2.16,我们可以在suites、classes、methods使用threadCountSuites, threadCountClasses和threadCountMethods参数限制线程数量。如果只指定threadCount参数,maven-surefire-plugin会试图优化suites, classes和methods的线程数量,并且重新使用线程。

举一个没有数量限制的线程的例子,有最大三个并行数量的线程执行suites:parallel=all, useUnlimitedThreads=true, threadCountSuites=3。

In the second example, the number of concurrent methods is not strictly limited: parallel=classesAndMethods, threadCount=8, threadCountClasses=3. Here the number of parallel methods is varying from 5 to 7. Accordingly parallel=all, but the sum of threadCountSuites and threadCountClasses must not exceed certain (threadCount - 1). Other combinations are possible with unspecified thread-count leaf. Make sure that the leaf is last from the order suites-classes-methods in parallel.
第二个例子是,并行方法的数量没有严格限制:parallel=classesAndMethods, threadCount=8, threadCountClasses=3。这里并行方法的数量从5到7。根据parallel=all,但是threadCountSuites和threadCountClasses的和不能超过一个确定的值(threadCount-1)。其它没有特定thread-count leaf的结合是可用的。

In the third example the thread-counts represent a ratio, e.g. for parallel=all, threadCount=16, threadCountSuites=2, threadCountClasses=3, threadCountMethods=5. Thus the concurrent suites will be 20%, concurrent classes 30%, and concurrent methods 50%.
第三个例子,thread-counts代表一个比例,例如parallel=all, threadCount=16, threadCountSuites=2, threadCountClasses=3, threadCountMethods=5。因此并行的套件是20%,并行的类是30%,并行的方法是50%。

Finally, the threadCount and useUnlimitedThreads may not be necessarily configured if the equivalent thread-counts are specified for the value in parallel.
最后,threadCount和useUnlimitedThreads不是一定要被配置,如果相同的线程数量在parallel中被指定。

The maven-surefire-plugin is trying to reuse threads, thus optimize the thread-counts, and prefers thread fairness. The optimization parallelOptimized of the number of Threads is enabled by default in terms of e.g. the number of Suite runners do not necessarily have to waste Suite’s Thread resources. If threadCount is used, then the leaf with unlimited thread-count may speed up especially at the end of test phase.
maven-surefire-plugin正在重新使用线程,因此优化线程数量和线程公平性。线程数量的parallelOptimized的优化被默认被启用,Suite runners的数量没有必要浪费套件的线程资源。如果使用threadCount,那么没有限制的线程数量可以加速测试阶段。

The parameters parallelTestsTimeoutInSeconds and parallelTestsTimeoutForcedInSeconds are used to specify an optional timeout in parallel execution. If the timeout is elapsed, the plugin prints the summary log with ERROR lines: “These tests were executed in prior to the shutdown operation”, and “These tests are incomplete” if the running Threads were interrupted.
parallelTestsTimeoutInSeconds和parallelTestsTimeoutForcedInSeconds参数用于在并行执行中指定可选的超时时间。如果时间到了,插件就会打印错误日志:“These tests were executed in prior to the shutdown operation”, 或者"These tests are incomplete" ,如果运行的线程被中断。

The important thing to remember with the parallel option is: the concurrency happens within the same JVM process. That is efficient in terms of memory and execution time, but you may be more vulnerable towards race conditions or other unexpected and hard to reproduce behavior.
需要记住的重要事:并行是在相同的JVM进程中进行的。对于内存和执行时间是有效的,但是对于竞争条件或其它不能预料和难以再现的行为,你可能会更加受到伤害。

The other possibility for parallel test execution is setting the parameter forkCount to a value higher than 1. The next section covers the details about this and the related reuseForks parameter. Using reuseForks=true (by default) and forking the test classes in reusable JVMs may lead to the same problem with shared static code across @BeforeClass class initializers if using parallel without forking. Therefore setting reuseForks=false may help however it would not guarantee proper functionality of some features, e.g. skipAfterFailureCount.
并行测试执行的另外一种方式给forkCount参数设置一个比1大的值。下面一节介绍这些和相关的reuseForks参数。使用reuseForks=true并且在可以重复使用的JVM中fork测试类可能会和不使用fork并行的@BeforeClass注解的类的共享静态代码导致相同的问题。因此设置 reuseForks=false可能会有帮助,然而它并不保证一些特性的恰当的功能,例如skipAfterFailureCount。

并行测试执行和单线程执行

As mentioned above the parallel test execution is used with specific thread count. Since of maven-surefire-plugin:2.18, you can apply the JCIP annotation @net.jcip.annotations.NotThreadSafe on the Java class of JUnit test (pure test class, Suite, Parameterized, etc.) in order to execute it in single Thread instance. The Thread has name maven-surefire-plugin@NotThreadSafe and it is executed at the end of the test run.
上面提到的parallel测试执行适合特定的线程数量一起使用的。从maven-surefire-plugin:2.18开始,你可以在JUnit测试类上应用JCIP 注解@net.jcip.annotations.NotThreadSafe,为了在一个单线程实例中执行它。这个线程的名字是maven-surefire-plugin@NotThreadSafe,并且他是在测试运行的最后被执行。

This way the parallel execution of tests classes annotated with @NotThreadSafe are forked in single thread instance (don’t mean forked JVM process).
@NotThreadSafe注解的类测试并行运行方式是在一个单独的线程实例中(不意味着在JVM进程中fork)。
If the Suite or Parameterized is annotated with @NotThreadSafe, the suite classes are executed in single thread. You can also annotate individual test class referenced by Suite, and the other unannotated test classes in the Suite can be subject to run in parallel. This way you can isolate conflicting groups of tests and still run their individual tests in parallel.
如果Suite或者Parameterized使用@NotThreadSafe注解,suite classes就会在一个单独的线程中执行。也可以Suite引用的单个测试类,另一个未注解的测试类就会并行运行。可以用这种方式隔离有冲突的测试,而仍然并行地运行它们的测试。

在多模块maven并行构建中并行执行maven-surefire-plugin插件

Maven core allows building modules of multi-module projects in parallel with the command line option -T. This multiplies the extent of concurrency configured directly in maven-surefire-plugin.
Maven核心允许使用命令行选项-T来允许构建多模块的项目的模块。这会加倍直接在maven-surefire-plugin插件中的并行程度。

Forked Test Execution

forkCount定义了maven-surefire-plugin插件并行执行测试的JVM进程的最大数量。如果取值以C结尾,那么这个值等于设定的值乘以CPU内核数。例如2.5C在4核机器上会产生10个执行测试的JVM进程。

reuseForks 被用于定义是否在一个测试类执行完后终止进程,并且给下一个测试创建一个新的进程(reuseForks=false),或者是否复用进程来执行下面的测试(reuseForks=true)。

The default setting is forkCount=1/reuseForks=true, which means that maven-surefire-plugin creates one new JVM process to execute all tests in one Maven module.
默认的设置是forkCount=1/reuseForks=true,意味着maven-surefire-plugin创建了一个新的JVM进程来执行一个Maven模块中所有的测试。

forkCount=1/reuseForks=false executes each test class in its own JVM process, one after another. It creates the highest level of separation for the test execution, but it would probably also give you the longest execution time of all the available options. Consider it as a last resort.
forkCount=1/reuseForks=false会挨个地执行每个测试类在他自己的JVM进程中。它创建了测试i执行的最高隔离级别,但它将很可能也给你所有可用选项的最长的执行时间。把它看作最后一个方法。

With the argLine property, you can specify additional parameters to be passed to the forked JVM process, such as memory settings. System property variables from the main maven process are passed to the forked process as well. Additionally, you can use the element systemPropertyVariables to specify variables and values to be added to the system properties during the test execution.
使用argLine属性,你可以指定传递给forked JVM进程的额外的参数,例如内存设置。来自主maven进程的系统属性变量也被传递给forked进程。另外,你也可以使用systemPropertyVariables元素来在测试运行期间指定变量和值添加到系统属性中。

You can use the place holder ${surefire.forkNumber} within argLine, or within the system properties (both those specified via mvn test -D… and via systemPropertyVariables). Before executing the tests, the surefire plugin replaces that place holder by the number of the actually executing process, counting from 1 to the effective value of forkCount times the maximum number of parallel executions in Maven parallel builds, i.e. the effective value of the -T command line argument of Maven core.

In case of disabled forking (forkCount=0), the place holder will be replaced with 1.

The following is an example configuration that makes use of up to three forked processes that execute the tests and then terminate. A system property databaseSchema is passed to the processes, that shall specify the database schema to use during the tests. The values for that will be MY_TEST_SCHEMA_1, MY_TEST_SCHEMA_2, and MY_TEST_SCHEMA_3 for the three processes. Additionaly by specifying custom workingDirectory each of processes will be executed in a separate working directory to ensure isolation on file system level.

联合使用forkCount和parallel

forkCount=0和forkCount=1/reuseForks=true可以和parallel结合使用。
reuseForks=false给每个测试类创建了一个新的JVM进程,使用parallel=classes将没有影响。但你仍然可以使用parallel=methods。

When using reuseForks=true and a forkCount value larger than one, test classes are handed over to the forked process one-by-one. Thus, parallel=classes would not change anything. However, you can use parallel=methods: classes are executed in forkCount concurrent processes, each of the processes can then use threadCount threads to execute the methods of one class in parallel.
当使用reuseForks=true并且forkCount值比1大,测试类会挨个地交给fork的进程。因此,parallel=classes将不会改变什么。然而,你可以使用parallel=methods:classes在forkCount并行进程中执行,每个进程可以使用threadCount线程来并行执行一个类中的方法。

Regarding the compatibility with multi-module parallel maven builds via -T, the only limitation is that you can not use it together with forkCount=0.

When running parallel maven builds without forks, all system properties are shared among the builder threads and surefire executions, therefore the threads will encounter race conditions when setting properties, e.g. baseDir, which may lead to changing system properties and unexpected runtime behaviour.

并行运行参数

  • <parallel>
    (TestNG provider)使用parameter参数时,TestNG将在独立的线程中运行所有的测试方法,除了彼此依赖的方法,它们将在相同的线程中按照顺序执行。
    (JUnit 4.7 provider)支持的值包括classes、methods,两个都是由threadCount控制运行在独立的线程中。
    从2.16(JUnit 4.7 provider)开始,both被弃用了,使用classesAndMethods。
    从2.16(JUnit 4.7 provider)开始,额外的参数值有:suites, suitesAndClasses, suitesAndMethods, classesAndMethods, all。
    默认情况下,Surefire不是并行地执行测试。你可以设置parallel参数为none,来显示地禁用并行执行(例如当执行覆盖率分析时禁用并行执行)。

  • <useUnlimitedThreads>
    (JUnit 4.7 provider) 指明线程池是无限的。parallel参数和classes/methods的实际数量将决定。设置为true将禁用perCoreThreadCount和threadCount。默认是false。

  • <perCoreThreadCount>
    指明threadCount, threadCountSuites, threadCountClasses, threadCountMethods是针对每个cpu内核的。默认为true。

  • <threadCountClasses>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值