当前位置: 首页 > news >正文

【JUnit实战3_20】第十一章:用 Gradle 运行 JUnit 测试实战

JUnit in Action, Third Edition

《JUnit in Action》全新第3版封面截图

写在前面
一直都想尝试用 Gradle 构建项目,毕竟 Gradle 的轻量和灵活总是让围城外面的人向往不已,但学习曲线的陡峭也让人望而却步。本书第 11 章刚出版时演示的最新版是 6.0,现在已经到 9.1 并且默认支持 Kotlin 而不再是 Groovy 了。但既然是实战类笔记,就必须在本地跑跑最新版,看看有什么不一样的地方。

第十一章:用 Gradle 运行 JUnit 测试

本章概要

  • Gradle 简介
  • Gradle 项目的设置
  • Gradle 插件的用法
  • 从零创建 Gradle 项目、并用 JUnit 5 进行测试
  • 对比 GradleMaven

本章对 Gradle 介绍十分简要,因为截止 2020 年成书时,全球使用 Gradle 构建的项目也仅占约 25%,近年来的市场份额也没有太大的变化;再加上 Gradle 本身的学习曲线比较陡峭,当时最新的 v6.0 版对 @Display 注解的支持也存在一些问题,相关介绍就更少了。因此,实测本章内容时将采用最新的 v9.0.0 进行验证,并结合 附录 B 对一些基础用法做一些介绍。


11.1 Gradle 简介

Gradle(https://gradle.org)是继 Apache Ant(2000 年)和 Apache Maven(2004 年)后,由 Google 于 2012 年推出的、基于 GroovyDSL 语言开发的新一代项目构建工具。

Gradle(读作:/ˈɡreɪdəl/),该名称的设计灵感源于 GroovyAnt 的结合1;其单词本意为等级、阶梯、渐变,这也恰好暗含了 Gradle 的另一个关键特性:增量构建Gradle 的问世主要是为了在 Ant 的灵活性和 Maven 的规范性之间找到一个最佳平衡点,并利用一门真正的编程语言(即 Groovy,目前默认使用 Kotlin)来打破 XML 的固有局限性。

知识拓展:增量构建

所谓的增量构建,是指 Gradle 能通过分析任务的输入和输出,智能地判断哪些任务是最新的、哪些需要重新执行。由于只执行那些“已升级”或“已变更”的部分,从而极大地提升了构建速度。这种 一步步升级/构建 的过程,与 阶梯 的意象非常吻合。

Groovy 是一门典型的 DSL(domain-specific language,特定领域语言) 语言。它兼容 Java 语法,支持面向对象编程,且可以在 Java 虚拟机上运行。

DSL 是一种专门解决特定应用领域问题的计算机语言,常见的还包括 SQL、正则表达式、AWKScalaKotlin 等;其核心理念是为了 在特定领域提升表达效率和清晰度,让代码或配置读起来更像是某个领域的专家在描述问题,而不是程序员编写的通用逻辑。

DSL 概念相对立的另一个概念即 GPLGeneral-Purpose Language,即通用编程语言),例如 JavaPythonC++ 等语言。GPL 旨在解决各种领域的复杂计算问题,能够提供完备的编程抽象(变量、循环、函数等),功能强大,但学习曲线也相对陡峭。

而在项目构建领域,践行 DSL 理念的一个重要成果,就是基于 Groovy 语言的 Gradle

11.2 Gradle 的安装与基础配置

本节根据 附录 B 整理,实测时 Gradle 官网 已经正式发布 v9.1.0

Fig11.1

对应的 Java 版本也升级到了 JDK17。为了增强实测的时效性,本地选用最新版进行演示。

zip 安装包下载地址:https://gradle.org/releases/

下载成功后,将 Gradle 安装包解压到某个目录下(如 D:\gradle-9.1.0\):

Fig11.2

然后按如下步骤配置环境变量:

# 打开系统高级设置窗口
> systemPropertiesAdvanced

新建环境变量 GRADLE_HOME,对应的值为刚才解压的 Gradle 路径 (D:\gradle-9.1.0\):

Fig11.3

然后调用该变量,将 %GRADLE_HOME%\bin 添加到 Path 中:

Fig11.4

再用同样的方式创建一个系统变量 GRADLE_USER_HOME,对应的值为本地 Maven 仓库的路径,这样就能和 Maven 共享本地依赖;否则 Gradle 在构建项目时会默认在 {USER_HOME}/.gradle/ 文件夹下重新下载所需依赖,浪费磁盘空间:

Fig11.5

确认后验证配置:

> gradle -version------------------------------------------------------------
Gradle 9.1.0
------------------------------------------------------------Build time:    2025-09-18 13:05:56 UTC
Revision:      e45a8dbf2470c2e2474ccc25be9f49331406a07eKotlin:        2.2.0
Groovy:        4.0.28
Ant:           Apache Ant(TM) version 1.10.15 compiled on August 25 2024
Launcher JVM:  21.0.6 (Oracle Corporation 21.0.6+8-LTS-188)
Daemon JVM:    C:\Program Files\Java\jdk-21 (no JDK specified, using current Java home)
OS:            Windows 10 10.0 amd64
> 

说明 Gradle 安装成功。

11.3 用 Gradle 创建一个项目

本节演示如何利用 Gradle 命令创建一个默认项目。

任意新建一个文件夹(例如上一章的 C:\junitbook\),然后命令行导航到该路径,并执行如下命令:

> mkdir flightmanagement | Out-Null
> cd flightmanagement
> gradle init
Starting a Gradle Daemon, 1 stopped Daemon could not be reused, use --status for detailsSelect type of build to generate:1: Application2: Library3: Gradle plugin4: Basic (build structure only)
Enter selection (default: Application) [1..4]Select implementation language:1: Java2: Kotlin3: Groovy4: Scala5: C++6: Swift
Enter selection (default: Java) [1..6]Enter target Java version (min: 7, default: 21):Project name (default: flightmanagement):Select application structure:1: Single application project2: Application and library project
Enter selection (default: Single application project) [1..2]Select build script DSL:1: Kotlin2: Groovy
Enter selection (default: Kotlin) [1..2] 2Select test framework:1: JUnit 42: TestNG3: Spock4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4]Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]> Task :init
Learn more about Gradle by exploring our Samples at https://docs.gradle.org/9.1.0/samples/sample_building_java_applications.htmlBUILD SUCCESSFUL in 50s
1 actionable task: 1 executed
> 

注意,最新版 Gradle 默认的构建脚本已经切换到 Kotlin 了,因此应该手动选择 Groovy,输入 2 后按 Enter 键继续(第 L34 行)。其余选项均保持默认设置即可。最后得到的项目结构如下:

> tree /f .
Folder PATH listing for volume OS
Volume serial number is 00000085 DA4A:6CB8
C:\JUNITBOOK\FLIGHTMANAGEMENT
│   .gitattributes
│   .gitignore
│   gradle.properties
│   gradlew
│   gradlew.bat
│   settings.gradle
│
├───app
│   │   build.gradle
│   │
│   └───src
│       ├───main
│       │   ├───java
│       │   │   └───org
│       │   │       └───example
│       │   │               App.java
│       │   │
│       │   └───resources
│       └───test
│           ├───java
│           │   └───org
│           │       └───example
│           │               AppTest.java
│           │
│           └───resources
└───gradle│   libs.versions.toml│└───wrappergradle-wrapper.jargradle-wrapper.properties
> 

接着删除默认生成的 org.example.App.java 以及对应的测试类 org.example.AppTest.java,改为书中指定的 Passenger 类和测试类 PassengerTest

# 删除默认的类和测试类
> rm -recurse -Force app\src\main\java\org, app\src\test\java\org

导入 IDEA 后添加新的 Passenger 类和测试类 PassengerTest

// 乘客实体类
package com.testeddatasystem.flights;public class Passenger {private String identifier;private String name;public Passenger(String identifier, String name) {this.identifier = identifier;this.name = name;}public String getIdentifier() {return identifier;}public String getName() {return name;}@Overridepublic String toString() {return "Passenger " + getName() +", with identifier: " + getIdentifier();}public static void main(String[] args) {final Passenger passenger = new Passenger("123-456-789", "John Smith");System.out.println(passenger);}
}

然后在 Passenger 类上按 Ctrl + Shift + T 自动创建测试类:

Fig11.6

添加测试逻辑如下:

package com.testeddatasystem.flights;import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.*;class PassengerTest {@Test@DisplayName("toString() method should match the desired content")void testToString() {final Passenger passenger = new Passenger("123-456-789", "John Smith");assertEquals("Passenger John Smith, with identifier: 123-456-789",passenger.toString());}
}

Shift + F10 快速运行该测试用例,得到如下结果:

Fig11.7

Maven 不同的是,Gradle 会在 app/build/ 目录下直接生成 HTML 格式的测试报表:

Fig11.8

用浏览器打开该文件,还可以看到原书中提到的 @DisplayName 注解显示异常的问题早已解决:

Fig11.9

最后,再按书中演示的步骤过一遍 Gradle 的相关构建命令。

先修改配置文件 app/build.gradle 中的主类引用:

application {// Define the main class for the application.mainClass = 'com.testeddatasystem.flights.Passenger'
}

然后运行命令 gradle run

Fig11.10

接着执行命令 gradle build

Fig11.11

最后是 gradle test

Fig11.12

Gradle 9.1.0 最新的默认配置脚本已经和书中的 6.0 大相径庭了(9.1 版已无法顺利编译 6.0 的配置脚本了),新 build.gradle 的完整内容如下:

/** This file was generated by the Gradle 'init' task.** This generated file contains a sample Java application project to get you started.* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/9.1.0/userguide/building_java_projects.html in the Gradle documentation.*/plugins {// Apply the application plugin to add support for building a CLI application in Java.id 'application'
}repositories {// Use Maven Central for resolving dependencies.mavenCentral()
}dependencies {// Use JUnit Jupiter for testing.testImplementation libs.junit.jupitertestRuntimeOnly 'org.junit.platform:junit-platform-launcher'// This dependency is used by the application.implementation libs.guava
}// Apply a specific Java toolchain to ease working on different environments.
java {toolchain {languageVersion = JavaLanguageVersion.of(21)}
}application {// Define the main class for the application.mainClass = 'com.testeddatasystem.flights.Passenger'
}tasks.named('test') {// Use JUnit Platform for unit tests.useJUnitPlatform()
}

关于上述配置的具体含义,详见 Gradle 官方文档:https://docs.gradle.org/current/userguide/userguide.html。

想深入了解 Gradle 各种用法的朋友,还可以参考作者推荐的一本参考书:《Gradle in Action》(Benjamin Muschko, Manning, 2014.02)。

11.4 拓展:Gradle 任务的创建

附录 B 中还介绍了几个关于 Gradle 任务的小例子,这里也在本地实测了一遍。

Gradle 是通过 构建文件build file)来管理项目。每个 Gradle 构建文件都能描述 一个或多个 项目,而项目则是由不同的 任务 构成。所谓的 Gradle 任务,是指通过运行构建文件执行的某项工作内容,如编译某些类、创建 JAR 包、生成 Javadoc 文档、或将归档文件发布到 repository 仓库等等。构建或测试项目所需的操作都可以通过 Gradle 任务来定义和执行。

Gradle 还有个 闭包 的概念。闭包代表了某个独立的代码块,既可以接收参数,也可以有返回值。

Gradle 构建文件的默认名称为 build.gradle,因此可以利用该文件在桌面新建一个示例文件夹 gradleTest,然后执行下列命令,体验一下 Gradle 任务的相关操作:

# 初始化示例文件夹
> (pwd).Path
C:\Users\ad\Desktop
> mkdir gradleTest | Out-Null
> cd gradleTest# 示例1:创建一个 gradle 配置脚本
> vim build.gradle
> cat build.gradle
task junit {print "JUnit in Action"
}
# 执行 gradle 任务 junit(静默模式)
> gradle -q junit
JUnit in Action 0% CONFIGURING [79ms]# 示例2:运行带依赖关系的 gradle 任务
> vim build.gradle
> cat build.gradle
task junit {print "JUnit in Action"
}task third (dependsOn: 'junit') {println ", third edition"
}
# 执行任务 third
> gradle -q third
JUnit in Action, third edition# 示例3:运行带依赖关系、且任务中包含多个阶段的复杂任务
> vim build.gradle
> cat build.gradle
task junit {print "JUnit "doFirst {print "Action"}doLast {print ", "}
}task third (dependsOn: 'junit') {print "in "doFirst {print "third "}doLast {println "edition"}
}
# 执行复杂任务 third
> gradle -q third
JUnit in Action, third edition
> 

其中的 dependsOndoFirstdoLast 都是 Gradle API 中的固定写法,不可随意变更。具体用法详见 Gradle 官方文档。

11.5 对比 GradleMaven

11.5.1 核心理念对比

MavenGradle
主要特点声明式、标准化声明式 + 命令式、高度灵活
构建语言XML (pom.xml)Groovy / KotlinDSL 语言(build.gradlebuild.gradle.kts
核心原则约定优于配置约定优于配置,但可轻松覆盖约定配置

11.5.2 Ant、Maven、Gradle 横向对比

由于书中并未展开讨论 MavenGradle 的区别和联系,这里借用 Code0cean 大佬在博文《Gradle快速入门学习》中归纳的异同点:

对比维度AntMavenGradle
构建性能最高最低居中
仓库维护开发者自行维护Maven 仓库支持多种远程仓库
依赖管理Ivy 管理GAV 坐标管理GNV 坐标管理
插件支持实现方便实现较难实现方便
遵循特定目录结构✔️✔️
配置文件XML 文件(最繁琐)XML 文件代码脚本,便于写业务逻辑
侧重点小型项目构建项目包管理大型项目构建
目前地位使用较少主流未来趋势

11.5.3 构建工具选型建议

场景推荐工具理由
传统 Java EE / Spring 项目Maven项目结构标准,依赖管理简单,团队学习成本低,稳定性高。
Android 开发Gradle官方唯一支持,无其他选择。
大型、复杂、多项目构建Gradle卓越的性能和灵活性,能有效管理复杂的项目依赖和构建逻辑。
需要高度自定义构建流程Gradle用代码编写构建逻辑的能力是决定性优势。
初创团队或快速原型Maven简单的 pom.xml 可以快速搭建项目,避免在构建工具上花费过多时间。
追求极致构建速度Gradle增量构建和构建缓存带来的性能提升是碾压性的。

  1. Gradle 创始人 Hans Dockter 曾在多次访谈和演讲中提到,该名字意在传达它是一款基于 Groovy 的、建立在 Ant 最佳理念之上的构建工具,并将其提升到一个新的水平。 ↩︎

http://www.dtcms.com/a/553153.html

相关文章:

  • TouchDIVER Pro 触觉手套:Weart把火星岩石触感、手术操作感搬进 XR
  • 极不均匀电场的强垂直分量和弱垂直分量
  • 直播卡顿?会议割裂?视频直播点播平台EasyDSS全新升级,一平台终结音视频“老大难”!
  • Dotnet使用System.Xml.Serialization处理Xml序列化
  • 【JUnit实战3_19】第十章:用 Maven 3 运行 JUnit 测试(下)
  • wordpress 禁止过滤张家口seo
  • 网站建设的流程该怎么确定自己怎么设计logo制作
  • 3.游戏逆向-pxxx-对照UE源码和IDA分析GName偏移(ida中calloff开头地址的说明)
  • AR智能巡检:开启工业运维的“透视眼”
  • PhotoQt,一款轻量级图片浏览器
  • 什么是一级boot和二级boot
  • 网站开发师招聘网站建设几个要素
  • Java语言处理Js文件内容格式化
  • 力扣Hot100--哈希表--day01
  • 鸿蒙技术知多点,技术深入、鸿蒙开发实战分享(一)——下载功能按钮与全局悬浮窗联动实战开发
  • 安科瑞暖通空调解决方案可覆盖分体空调、中央空调和多联机等类型空调系统,有效帮助用户实现空调系统节能降本
  • 用php做购物网站视频网站建设 翰臣科技公司
  • 本地音乐库嫌麻烦?PlaylistDL+cpolar打造“随身听”云端曲库!
  • 巩义网站建设定制电子商务系统网站开发总结
  • Excel怎么在下拉菜单中选择计算方式?
  • PHY6252国产蓝牙低成本透传芯片BLE5.2智能灯控智能家居
  • unity之线框模式
  • h5游戏免费下载:小飞鱼?
  • 【设计模式】享元模式(Flyweight)大白话讲解!
  • seo网站优化知识网站设计师的工作环境
  • 浅谈onlyoffice开发全流程(一、基础介绍)
  • 金仓KRDS云数据库服务管控平台:构建高效智能的数据库运维体系
  • GMI Cloud:如何构建全球化高性能分布式推理服务?
  • Linux入门攻坚——52、drbd - Distribute Replicated Block Device,分布式复制块设备-1
  • Threat Report ATTCK Mapper(TRAM)安装与配置手册