[maven] scopes & 管理 & profile & 测试覆盖率

[maven] scopes & 管理 & profile & 测试覆盖率

这里将一些其他的特性和测试覆盖率(主要是 jacoco)

scopes

maven 的 scope 主要就是用来限制和管理依赖的传递性,简单的说就是,每一个 scope 都有其对应的特性,并且会决定依赖包在打包和运行时是否会被使用

这里主要谈论的差别是 compile classpath 和 runtime classpath,前者是编译时存在的环境,后者是运行时存在的环境。

总共有 6 个 scopes

  • compile (default)

    这个是默认的 scope,这个 scope 下的依赖会被打包到代码的最终代码里,它也代表着该依赖会被保存到 compile classpath 和 runtime classpath,粗暴的理解就是,打包好的 jar/war 文件会包含 runtime classpath 的代码

  • provided

    这个 scope 代表着在部署时,JDK 或者容器在运行时会提供该依赖,所以在 compile classpath 可以找到这个依赖,但是 runtime classpath 中不会

    例子就是 tomcat 这种 servlet api,编译时肯定是需要的,但是部署时肯定,环境里自己会启一个 servlet,因此 runtime classpath 不需要包涵

  • runtime

    这个 scope 意味着依赖在编译时不需要,但是运行时需要,比如说 JDBC driver

  • test

    顾名思义,只需要用在编译和测试,不会打包到最终的代码里

  • system

    这个挺少用的,因为一旦用它就代表着要用到 systemPath 相关,也就会变得非常依赖于系统,似的其可移植性变低

  • import

    比较特殊的 scope,用在 BOM 这种特殊的依赖,主要用来管理其他依赖版本

目前来说,从 central repo 上拉下来的 scope 还是比较准的,比如说 junit 相关的 scope 就是 test,不过这也可以按需修改。

项目管理

这里分为三个部分:

  • 依赖管理
  • 插件管理
  • 版本管理

主要应用场景都是对于依赖/插件的版本控制。重载版本的情况下,越下层(靠近执行项目的 pom)的值会取代上层设置的值

依赖管理

这个主要是通过在父元素中实现 dependencyManagement,这样子元素中就不用重新声明版本,方便进行统一管理。

在父元素中定义 junit 的版本:

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">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.goldenaarcher.product</groupId>
	<artifactId>productparent</artifactId>
	<version>1.0</version>
	<packaging>pom</packaging>

	<name>productparent</name>
	<!-- FIXME change it to the project's website -->
	<url>http://www.example.com</url>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>4.11</version>
				<scope>test</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<modules>
		<module>productservices</module>
		<module>productweb</module>
	</modules>
</project>

这个时候,如果子项目中重新声明了版本,eclipse 就会出现这样的报错:

子项目中的 pom 荏苒需要按需定义使用的依赖,只不过就可以跳过版本声明,方便统一管理

插件管理

插件管理有个相似的 pluginManagement,不过它需要被放到 build 下:

xml 复制代码
	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.8.0</version>
					<configuration>
						<release>17</release>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

同理,子项目中也是需要声明同样的插件,但是可以不用实现 versionconviguration

版本管理

除了直接将版本写到 version 中,如果一些依赖(如 spring 全家桶)都需要使用同一个版本,与其重复 cv,也可以在 properties 中声明版本变量,方便管理:

xml 复制代码
	<properties>
		<java.version>17</java.version>
		<junit.version>5.10.0</junit.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.junit.jupiter</groupId>
				<artifactId>junit-jupiter-engine</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>
					<version>3.8.0</version>
					<configuration>
						<release>${java.version}</release>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

profiles

profile 是一些配置型的内容,可以用来重写默认值。

maven 中也可以用不同的项目家在加载不同的配置文件,祈祷方便管理的作用。

创建新项目

选择 quickstart 创建一个新的 demo 项目即可

创建配置文件

这里的 profile 和 main 同级,新建 3 个案例即可:

bash 复制代码
❯ tree src
src
├── main
│   ├── java
│   │   └── com
│   │       └── goldenaarcher
│   │           └── maven
│   │               └── profiledemo
│   │                   └── App.java
│   └── profiles
│       ├── dev
│       │   └── application.properties
│       ├── prod
│       │   └── application.properties
│       └── test
│           └── application.properties
└── test
    └── java
        └── com
            └── goldenaarcher
                └── maven
                    └── profiledemo
                        └── AppTest.java

里面的内容也很简单:

bash 复制代码
❯ cat src/main/profiles/dev/application.properties
db.url=devurl
db.userName=dev
db.password=dev%

其实 profiles 也可以放在其他地方,我记得一个项目是放到 resources 里,这点看项目习惯

配置 profile

profile 直接放在 xml 下即可:

xml 复制代码
	<profiles>
		<profile>
			<id>dev</id>
			<properties>
				<build.profile.id>dev</build.profile.id>
			</properties>
			<build>
				<resources>
					<resource>
						<directory>src/main/profiles/dev</directory>
					</resource>
				</resources>
			</build>
		</profile>

		<profile>
			<id>prod</id>
			<properties>
				<build.profile.id>prod</build.profile.id>
			</properties>
			<build>
				<resources>
					<resource>
						<directory>src/main/profiles/prod</directory>
					</resource>
				</resources>
			</build>
		</profile>

		<profile>
			<id>test</id>
			<properties>
				<build.profile.id>test</build.profile.id>
			</properties>
			<build>
				<resources>
					<resource>
						<directory>src/main/profiles/test</directory>
					</resource>
				</resources>
			</build>
		</profile>
	</profiles>

只有一个 profile 的话不需要设置 id,有一个以上不设置会报错

profile 使用案例

命令行执行 profile

语法为: mvn <lifecycle-phase> -P<profile-name>

如:

bash 复制代码
❯ mvn install -Pdev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< com.goldenaarcher.maven:profiledemo >-----------------
[INFO] Building profiledemo 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ profiledemo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ profiledemo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/usr/study/maven/profiledemo/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ profiledemo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/usr/study/maven/profiledemo/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ profiledemo ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/usr/study/maven/profiledemo/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ profiledemo ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.goldenaarcher.maven.profiledemo.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.022 s - in com.goldenaarcher.maven.profiledemo.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ profiledemo ---
[INFO] Building jar: /Users/usr/study/maven/profiledemo/target/profiledemo-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ profiledemo ---
[INFO] Installing /Users/usr/study/maven/profiledemo/target/profiledemo-0.0.1-SNAPSHOT.jar to /Users/usr/.m2/repository/com/goldenaarcher/maven/profiledemo/0.0.1-SNAPSHOT/profiledemo-0.0.1-SNAPSHOT.jar
[INFO] Installing /Users/usr/study/maven/profiledemo/pom.xml to /Users/usr/.m2/repository/com/goldenaarcher/maven/profiledemo/0.0.1-SNAPSHOT/profiledemo-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.714 s
[INFO] Finished at: 2023-09-14T22:44:31-04:00
[INFO] ------------------------------------------------------------------------

如果解压打包好的 jar 文件,就能看到里面的 application.properties 内容如下:

bash 复制代码
❯ cat target/profiledemo-0.0.1-SNAPSHOT/application.properties
db.url=devurl
db.userName=dev
db.password=dev%
eclipse 中设置

这个在 project properties 修改就行:

jacoco 代码覆盖率

sonarqube 执行失败

jacoco

修改 pom:

xml 复制代码
    <build>
		<plugins>
			<plugin>
				<groupId>org.jacoco</groupId>
				<artifactId>jacoco-maven-plugin</artifactId>
				<version>0.8.7</version>
				<executions>
					<execution>
						<goals>
							<goal>prepare-agent</goal>
						</goals>
					</execution>
					<execution>
						<id>report</id>
						<phase>test</phase>
						<goals>
							<goal>report</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
    </build>

这个 plugin 放到 pluginManagement 下管理会报错,但是拉出来直接放到 build 下就好了,原因未明,从 Stack Overflow 上找到的解决方法:maven jacoco: not generating code coverage report

简单的过一遍 xml 的配置,goal 在 [maven] maven 简述及使用 maven 管理单个项目 提过了,execution 没有。

goal 是 plugin 提供的,这里只是负责调用。

execution 是用来配置 goal 应该在哪个 phase 中执行,这里有两个 execution,第一个 goal 就是 jacoco 提供的 prepare-agent,其他忽略代表着会从头开始执行。

第二个 execution 指定的是生成报告的阶段,生成测试报告的 phase 应该是测试,所以就是在测试这个 phase 执行 report 这个 goal。

运行结果:

bash 复制代码
# 这里需要用verify不能用test,test会跳过report
❯ mvn clean verify
[INFO] Scanning for projects...
[INFO]
[INFO] -------------< com.goldenaarcher.product:productservices >--------------
[INFO] Building productservices 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ productservices ---
[INFO] Deleting /Users/usr/study/maven/parent/productservices/target
[INFO]
[INFO] --- jacoco-maven-plugin:0.8.7:prepare-agent (default) @ productservices ---
[INFO] argLine set to -javaagent:/Users/usr/.m2/repository/org/jacoco/org.jacoco.agent/0.8.7/org.jacoco.agent-0.8.7-runtime.jar=destfile=/Users/usr/study/maven/parent/productservices/target/jacoco.exec
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ productservices ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/usr/study/maven/parent/productservices/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ productservices ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 5 source files to /Users/usr/study/maven/parent/productservices/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ productservices ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/usr/study/maven/parent/productservices/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ productservices ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /Users/usr/study/maven/parent/productservices/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ productservices ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.goldenaarcher.product.dao.ProductDAOImplTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.07 s - in com.goldenaarcher.product.dao.ProductDAOImplTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- jacoco-maven-plugin:0.8.7:report (report) @ productservices ---
[INFO] Loading execution data file /Users/usr/study/maven/parent/productservices/target/jacoco.exec
[INFO] Analyzed bundle 'productservices' with 3 classes
[INFO]
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ productservices ---
[INFO] Building jar: /Users/usr/study/maven/parent/productservices/target/productservices-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.440 s
[INFO] Finished at: 2023-09-15T00:01:59-04:00
[INFO] ------------------------------------------------------------------------

可以看到,运行到测试这里,jacoco 的 goal 被执行了:jacoco-maven-plugin:0.8.7:report (report) @ productservices,最终生成报告的目录与结果:

bash 复制代码
❯ tree target/site
target/site
└── jacoco
    ├── com.goldenaarcher.product.bo
    │   ├── ProductBOImpl.html
    │   ├── ProductBOImpl.java.html
    │   ├── index.html
    │   └── index.source.html
    ├── com.goldenaarcher.product.dao
    │   ├── ProductDAOImpl.html
    │   ├── ProductDAOImpl.java.html
    │   ├── index.html
    │   └── index.source.html
    ├── com.goldenaarcher.product.dto
    │   ├── Product.html
    │   ├── Product.java.html
    │   ├── index.html
    │   └── index.source.html
    ├── index.html
    ├── jacoco-resources
    │   ├── branchfc.gif
    │   ├── branchnc.gif
    │   ├── branchpc.gif
    │   ├── bundle.gif
    │   ├── class.gif
    │   ├── down.gif
    │   ├── greenbar.gif
    │   ├── group.gif
    │   ├── method.gif
    │   ├── package.gif
    │   ├── prettify.css
    │   ├── prettify.js
    │   ├── redbar.gif
    │   ├── report.css
    │   ├── report.gif
    │   ├── session.gif
    │   ├── sort.gif
    │   ├── sort.js
    │   ├── source.gif
    │   └── up.gif
    ├── jacoco-sessions.html
    ├── jacoco.csv
    └── jacoco.xml

6 directories, 36 files

sonarqube

sonarqube 也是一个挺好用的代码测试工具,不过它需要修改本机 proxy,并启动一个本地服务器去执行剩下的操作,很不幸的是工作机的 proxy 没法改,所以这里就......

它的运行方式还是挺简单的,sonarqube 提供了 sh/bat 文件,直接运行就能启动服务器,登陆后在 dashboard 生成一串登陆编号,maven 运行时添加登录编号 sonarqube 就可以对其进行分析,属于不太要修改 maven 配置的工具

相关推荐
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹4 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭4 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫5 小时前
泛型(2)
java
超爱吃士力架5 小时前
邀请逻辑
java·linux·后端
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石5 小时前
12/21java基础
java
李小白665 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp5 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶6 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb