要定义一个新的源组, sourceSets {}
块中引用它.下面是一个例子:
22.5.定义一个新的 source set
build.gradle
sourceSets {
intTest
}
当定义一个新的 source set, java 插件会为该 source set 添加一些如 Table 22.6, “Java plugin - source set dependency configurations”中所示的依赖配置关系. 可以使用这些配置来定义source set的编译和运行时依赖。
22.6.定义 source set 的依赖
build.gradle
sourceSets { intTest }
dependencies { intTestCompile 'junit:junit:4.12' intTestRuntime 'org.ow2.asm:asm-all:4.0' }
java 插件增加了一些如Table 22.2, “Java plugin - source set tasks”为该 source set组装 classes文件的任务,例如,对于一个叫 intTest的 source set,为此 source set编译classes任务运行gradle intTestClasses
完成。
22.7.编译一个 source set
输出
> gradle intTestClasses
:compileIntTestJava
:processIntTestResources
:intTestClasses
BUILD SUCCESSFUL
Total time: 1 secs
22.8.为 source set 组装 JAR
build.gradle
task intTestJar(type: Jar) { from sourceSets.intTest.output }
22.9.为 source set 生成 javadoc
build.gradle
task intTestJavadoc(type: Javadoc) {
source sourceSets.intTest.allJava
}
22.8.source set 运行测试
build.gradle
task intTest(type: Test) {
testClassesDir = sourceSets.intTest.output.classesDir
classpath = sourceSets.intTest.runtimeClasspath
}
Javadoc task 是 Javadoc 的一个实例. 它支持 Javadoc 的核心选项和可执行的 Javadoc 的 reference documentation 中描述的标准JavaDoc的选项.
有关支持 Javadoc 选项的完整列表, 请参阅以下类的API文档:CoreJavadocOptions 和 StandardJavadocDocletOptions.
t22.10.java 插件- javadoc 配置
任务属性 | 类型 | 默认值 |
---|---|---|
classpath | FileCollection | sourceSets.main.output + sourceSets.main.compileClasspath |
source | FileTree.可以设置为在Section 15.5, “Specifying a set of input files”中描述的任何值 | sourceSets.main.allJava |
destinationDir | File | docsDir/javadoc |
title | String | project 的 name 和 version |
clean 任务是一个 Delete 的实例. 它只是删除 dir 属性指定的目录.
Table 22.11.java 插件 - Clean 的属性
任务属性 | 类型 | 默认值 |
---|---|---|
dir | File | buildDir |
Java 插件使用 Copy 任务处理资源. 它为项目每个 source set 都增加了一个实例.
可以参考Section 15.6, “Copying files” 获取关于copy任务的信息.
t22.12.java 插件- ProcessResources 的属性
任务属性 | 类型 | 默认值 |
---|---|---|
srcDirs | Object.Section 15.5, “Specifying a set of input files” | sourceSet.resources |
destinationDir | File. Section 15.1, “Locating files” | sourceSet.output.resourcesDir |
java 插件为项目的每一个 source set 增加了一个 JavaCompile 实例, 最常见的配置选项如下所示:
表22.13.java 插件-编译配置
任务属性 | 类型 | 默认值 |
---|---|---|
classpath | FileCollection | sourceSet.compileClasspath |
source | FileTree, 可以在Section 15.6, “Copying files”中查看. | sourceSet.java |
destinationDir | File. | sourceSet.output.classesDir |
默认情况下 java 的编译运行在 Gradle 中的进程. 设置 option.fork
为 true
会使编译在一个单独的进程中运行, 在Ant中运行 javac任务意味着一个新进程将被拆封为多个编译任务,这会减慢编译。
相反的, Gradle的直接编译集成(见上文)在编译过程中将尽可能地重复使用相同的进程. 在所有情况下由options.forkOptions指定的选项会被实现.
从Gradle2.1开始,可以使用Java增量编译,此功能正在孵化,参见[JavaCompile](https://docs.gradle.org/current/dsl/org.gradle.api.tas ks.compile.JavaCompile.html)如何启用这个功能. 增量编译的主要目标如下:
- 避免在没必要编译的java编译资源上浪费时间. 这意味着更快构建, 尤其是在改变一些class与jar的时候, 不需要再次编译那些不依赖这些class与jar的文件.
- 尽可能地少输出class. 类不需要重新编译意味着保持输出目录不变。一个示例场景中,真正使用JRebel的真正有用的是 - 越少的输出类被改变,JVM可以使用越快刷新。
更高级的增量编译:
- 检测陈旧类的设置是否正确是以牺牲速度为代价的, 该算法分析字节码并与编译器直接交互(非私有常量内联), 依赖传递等.
e.g. 当一个类的公共常量改变后, 希望避免由编译器编译内联常数产生的问题, 我们将调整算法和缓存以便增量Java编译可以是每编译任务的默认设置。
- 为了使增量编译快,缓存会分析class的结果和jar快照。最初的增量编译应该会慢于cold caches.
test任务是Test的一个实例.它会在测试source set自动检测并执行所有的单元测试,并且在测试执行完成后会生成一份测试报告.task任务支持JUnit和TestNG.在Test查看完整地API.
测试从main构建过程中分离出来的, 运行在一个单独的JVM中执行.Test任务允许控制这些如何发生. 有许多属性用于控制测试过程如何启动.这包括使用诸如系统属性,JVM参数和Java可执行文件。
可以指定是否要并行执行测试. Gradle通过同时运行多个测试进程提供并行执行测试. 每个测试进程在同一时间只能执行一个测试, 为了充分利用这一特性, 一般不需要为tests任务做什么特别的设置,maxParallelForks
属性指定测试进程在同一时间运行的最大进程数. 默认值是1,意味着不执行并行测试.
测试过程中设置org.gradle.test.worker
系统属性为该测试过程的唯一标识符, e.g. 在文件名或其他资源标识符的唯一标识符。
可以指定一些测试任务在已执行了一定数量的测试后重新运行. 这可能是一个非常好的方式替代测试进程中的大量的堆. forkEvery
属性指定测试类的在测试过程执行的最大数目。默认的是执行在各测设进程中不限数量的测试。
该任务有一个ignoreFailures
属性来控制在测试失败时的行为。测试任务总是执行每一个检测试验.它停止构建之后,如果ignoreFailures
是false
,说明有失败的测试。ignoreFailures
的默认值是false
。
testLogging
属性允许配置哪个测试事件将被记录,并设置其log等级。默认情况下,将记录每一个失败的测试简明消息。详见TestLoggingContainer如何按需求调整测试记录。
测试任务提供了Test.getDebug()属性,可使JVM等待调试器附加到5005端口后在进行调试.
通过调用--debug-JVM
任务选项,这也可以启用调试任务(Gradle1.12)。
从Gradle1.10开始,可以根据测试任务名进行特点的任务测试,过滤与在构建脚本的段落中引入/排除测试任务(-Dtest.single, test.include and friends)是两种不同的机制.
后者是基于文件, 如测试实现类的物理位置. 选择文件级的测试会不支持那些被测试等级过滤掉的一些有趣的测试脚本.
下面的这些有些已经被实现, 有些是将来会实现的:
- 过滤特定等级的试验方法;执行单个测试方法
- 通配符”*”支持任意字符匹配
- 命令行选项”–tests”用以设置测试过滤器.对经典的 ‘执行单一测试方法’用例尤其有用. 当使用命令行选项的时候,在构建脚本中声明的包含过滤器被忽略。
- Gradle过滤测试框架API的限制.一些高级的综合性测试无法完全兼容测试过滤,但是,绝大多是测试和用例可以被熟练地处理.
- 测试过滤取代基于选择文件的测试,后者在未来可能会完全被取代. 完善测试过滤的API, 并增加不同的过滤器
22.11.过滤测试的构建脚本
build.gradle
test{
filter{
//包括在测试的任何具体方法
includeTestsMatching "*UiCheck"
//包括所有包种的测试
includeTestsMatching "org.gradle.internal.*"
//包括所有的集成测试
includeTestsMatching "*IntegTest"
}
}
要了解更多详细信息和示例,请参见TestFilter。
使用命令行选项的一些例子:
* gradle test –tests org.gradle.SomeTest.someSpecificFeature
* gradle test –tests *SomeTest.someSpecificFeature
* gradle test –tests *SomeSpecificTest
* gradle test –tests all.in.specific.package*
* gradle test –tests *IntegTest
* gradle test –tests *IntegTest*ui*
* gradle someTestTask –tests *UiTest someOtherTestTask –tests *WebTest*ui
如上所述该机制已经被测试过滤取代
e.g.
* gradle -Dtest.single=ThisUniquelyNamedTest test
* gradle -Dtest.single=a/b/ test
* gradle -DintegTest.single=*IntegrationTest integTest
* gradle -Dtest.single=:proj1:test:Customer build
* gradle -DintegTest.single=c/d/ :proj1:integTest
测试任务检测哪些类是通过检查编译测试类的测试类。默认情况下它会扫描所有.calss文件.可以自定义包含/排除哪些类需不要要被扫描.所使用不同的测试框架(JUnit/ TestNG)时测试类检测使用不同的标准。
当使用JUnit,我们扫描JUnit3和JUnit4的测试类。
如果任一下列条件匹配,类被认为是一个JUnit测试类:
* 类或父类集成自TestCase或GroovyTestCase
* 类或父类有@RunWith注解
* 类或者父类中的方法有@Test注解
当使用TestNG,扫描注解了@Test的方法。
需要注意的是抽象类不执行。Gradle还扫描了继承树插入测试classpath中的jar文件。
如果不想使用测试类的检测,可以通过设置scanForTestClasses为false禁用它。这将使得测试任务只使用包含/排除找到测试类。如果scanForTestClasses是false而且没有包含/排除指定模式, “**/*Tests.class”,”**/*Test.class”,与”**/*Abstract*.class”分别为包含/排除的默认值.
JUnit和TestNG允许为测试方法精密分组.
对于分组JUnit的测试类与测试方法,JUnit4.8引入了类别的概念.reference该测试任务允许您设定JUnit包括或者排除某些类的规范。
22.12.JUnit分类
build.gradle
test { useJUnit { includeCategories 'org.gradle.junit.CategoryA' excludeCategories 'org.gradle.junit.CategoryB' }
}
TestNG的框架有一个非常类似的概念。在TestNG的,可以指定不同的测试组。 测试分组应包括或排除在测试任务进行配置了的测试执行.
22.13.TestNG分组测试
build.gradle
test { useTestNG { excludeGroups 'integrationTests' includeGroups 'unitTests' }
}
测试任务默认生成以下结果.
+ 一份HTML测试报告
+ 一个与Ant的JUnit测试报告任务兼容的XML.这个格式与许多其他服务兼容, 如CI serves
+ 结果是有效的二进制,测试任务会从这些二进制结果生成其他结果。
有一个独立的TestReport任务类型会根据一些Test任务实例生成的二进制源码生成一个HTML报告.
使用这种测试类型,需要定义一个destinationDir,里面包括测试结果的报告.
22.14.创建单元测试报告子项目
build.gradle
subprojects {
apply plugin: 'java'
// Disable the test report for the individual test task
test {
reports.html.enabled = false
}
}
task testReport(type: TestReport) {
destinationDir = file("$buildDir/reports/allTests")
// Include the results from the `test` task in all subprojects
reportOn subprojects*.test
}
应该注意的是,TestReport型组合来自多个测试任务的结果,需要聚集个别测试类的结果。这意味着,如果一个给定的测试类是由多个测试任务执行时,测试报告将会包括那些类, 但是很难区分该输出结果分别是出自哪个类.
TestNG支持参数化方法, 允许一个特定的测试方法使用不同的输入被执行多次。Gradle会在测试报告中包含该方法的参数值.
给出一个叫aTestMethod的测试方法,该方法有两个参数, 在测试报告中会根据名字报告: aTestMethod(toStringValueOfParam1, toStringValueOfParam2)
. 这很容易识别的参数值的特定迭代.
表22.14.Java插件-测试属性
任务属性 | 类型 | 默认值 |
---|---|---|
testClassesDir | File | sourceSets.test.output.classesDir |
classpath | FileCollection | sourceSets.test.runtimeClasspath |
testResultsDir | File | testResultsDir |
testReportDir | File | testReportDir |
testSrcDirs | List | sourceSets.test.java.srcDirs |
jar 任务创建包含项目的类文件和资源的 JAR 文件. JAR 文件在 archives 的依赖配置中是作为一个 artifact 的声明. 这意味着, JAR 是相关项目一个可用的 classpath. 如果上传项目到存储库, 这个 JAR 会被声明为依赖描述符的一部分.
可以在Section 15.8, “Creating archives”与Chapter 51, Publishing artifacts中了解更多关于 JAR 与 archives 与 artifact configurations 协同工作的更多细节.
每个 jar 或 war 对象有一个 manifest 属性做为Manifest单独的实例,
当生成存档, 一个对应MANIFEST.MF文件被写入到档案中.
22.15.MANIFEST.MF的定制
build.gradle
jar {
manifest {
attributes("Implementation-Title": "Gradle",
"Implementation-Version": version)
}
}
可以创建一个 manifest 的独立实例.
可以使用如共享 jar 之间的 manifest 的信息.
22.16.创建一个manifest对象
build.gradle
ext.sharedManifest = manifest {
attributes("Implementation-Title": "Gradle",
"Implementation-Version": version)
}
task fooJar(type: Jar) { manifest = project.manifest { from sharedManifest }
}
可以合并其他 manifest 到任何 Manifest 对象. 其它清单可能是通过文件路径描述或着像上所述, 引用另一个Manifest对象.
22.17.独立的MANIFEST.MF一个特定的归档
build.gradle
task barJar(type: Jar) {
manifest {
attributes key1: 'value1'
from sharedManifest, 'src/config/basemanifest.txt'
from('src/config/javabasemanifest.txt',
'src/config/libbasemanifest.txt') {
eachEntry { details ->
if (details.baseValue != details.mergeValue) {
details.value = baseValue
}
if (details.key == 'foo') {
details.exclude()
}
}
}
}
}
清单合并的顺序与声明语句的顺序相同, 如果基本清单和合并的清单都为相同的密钥定义值,那么合并清单将会被合并, 可以通过添加在其中您可以使用一个ManifestMergeDetails实例为每个条目实体完全自定义的合并行为。
声明不会立即被来自触发合并。这是延迟执行的,要么产生jar时,或要求写入effectiveManifest时.
可以很容易地写一个清单到磁盘。
22.17.独立的MANIFEST.MF一个特定的存档
build.gradle
jar.manifest.writeTo("$buildDir/mymanifest.mf")
如何上传archives Chapter 51, Publishing artifacts
JUnit的维基包含有关如何使用JUnit类工作的详细说明: https://github.com/junit-team/junit/wiki/Categories.
TestNG的文档包含关于测试组的更多详细信息: http://testng.org/doc/documentation-main.html#test-groups.
WAR插件扩展了Java插件,支持web应用组装成War文件.它默认禁用了Java插件JAR归档任务,并增加了一个默认的WAR归档任务。
使用war插件需要在构建脚本下包括以下内容
25.1.使用war插件
build.gradle
apply plugin 'war'
War插件会添加下列任务到项目.
t25.1.War插件-任务
任务名 | 依赖 | 类型 | 描述 |
---|---|---|---|
war | compile | War | 组装应用程序War文件 |
War插件由Java插件添加下列依赖任务.
t25.2.War插件-附加的依赖任务
任务名 | 依赖 |
---|---|
assemble | war |
p25.1.War插件-任务
t25.3.War插件-项目布局
文件夹 | 含义 |
---|---|
src/main/webapp | Web应用资源 |
War插件增加了名为 providedCompile和 providedRuntime的两个依赖配置.这两个配置有相同的作用域在编译或者运行时的配置,不同之处在于是否会将war文件归档.
很重要的一点是它们都会提供配置传递. e.g. 在任意的provided配置中添加了commons-httpclient:commons-httpclient:3.0
,该依赖依赖于commons-codec
,因为这个一个”provided”的配置,意味着这两个依赖都不会被加入你的WAR中, 即使commons-codec
库是一个显式的编译配置.
如果不希望出现这种传递行为,commons-httpclient:commons-httpclient:3.0@jar
这样声明provided依赖即可.
t25.4.War插件-目录配置
属性名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
webAppDirName | String | src/main/webapp | 在项目目录的web应用的资源文件夹名 |
webAppDir | File (read-only) | projectDir/webAppDirName | Web应用的资源路径 |
这些属性由一个WarPluginConvention公共对象提供
War任务默认会把src/main/webapp
的内容复制到归档目录的根目录.webapp文件夹下会包含一个WEB-INF
子文件夹,里面可能会有一个web.xml文件. 编译后的class文件会在WEB-INF/classes
下,所有runtime的依赖配置会被拷贝至WEB-INF/lib
下.
API文档中有更多关于War的信息.
25.2.定制War插件
build.gradle
configuration{
moreLibs
}
respositories{
faltDir {dirs "lib"}
mavenCentral()
}
dependencies{
compile module(":compile:1.0") {
dependency ":compile-transitive-1.0@jar"
dependency ":providedCompile-transitive:1.0@jar"
}
providedCompile "javax.servlet:servlet-api:2.5"
providedCompile module(":providedCompile:1.0") {
dependency ":providedCompile-transitive:1.0@jar"
}
runtime ":runtime:1.0"
providedRuntime ":providedRuntime:1.0@jar"
testCompile "junit:junit:4.12"
moreLibs ":otherLib:1.0"
}
war{
from 'src/rootContent' // 增加一个目录到归档根目录
webInf {from 'src/additionalWebInf'} // 增加一个目录到 WEB-INF 下
classpath fileTree('additionalLibs') // 增加一个目录到 WEB-INF/lib下.
classpath configurations.moreLibs // 增加更多地设置到 WEB-INF/lib 下.
webXml = file('src/someWeb.xml') // 复制xml文件到 WEB-INF/web.xml.
}
当然,可以用一个封闭的标签定义一个文件是否存打包到War文件中.
runtime
配置扩展了compile
配置.
—TBC—
—YCR—