一、Maven概述
1、课程介绍
Maven是一款用于管理和构建Java项目的工具,是apache旗下的一个开源项目。
Apache软件基金会,成立于1999年7月,是目前世界上最大的最受欢迎的开源 软件基金会,也是一个专门为支持开源项目而生的非盈利性组织。 开源项目:Welcome to The Apache Software Foundation | Apache Software Foundation
(1)依赖管理
方便快捷的管理项目依赖的资源(jar包)
无需手动导入jar包,只需要在pom.xml文件中声明即可

(2)项目构建
标准化的跨平台(Linux、Windows、MacOs)的自动化项目构建方式
传统项目构建方式需要一系列流程

而Maven的项目构建提供了项目的生命周期

项目构建的文件存放在target目录下

(3)统一项目结构
提供标准、统一的项目结构 传统的各编译软件的项目结构是不相通的,引入Maven后就可以使用同一个项目结构


2、Maven介绍
Apache Maven是一个项目管理和构建工具,它基于项目对象模型(POM)(project object madel)的概念,通过一小段描述信息来管理项目的构建。
作用:
方便的依赖管理
标准的项目构建流程
统一的项目结构
官网:Welcome to Apache Maven -- Maven

项目对象模型(POM)
XML
<!--描述当前项目信息。包名、项目名、版本-->
<groupId>com.itheima</groupId>
<artifactId>maven-project01</artifactId>
<version>1.0-SNAPSHOT</version>
<!--基于JDK哪个版本开发的 运行的时候是基于哪个JDK版本 字符集编码-->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
依赖管理模型(Dependency)
dependency里包括但不限于这些标签
XML
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.4</version>
<!--排除依赖-->
<exclusions>
<exclusion>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
仓库:用于存储资源,管理各种jar包。
本地仓库:自己计算机上的一个目录。
我的本地仓库地址:"D:\install\envresoce\maven\repository\commons-io\commons-io\2.6"
中央仓库:由Maven团队维护的全球唯一 的。仓库地址:Central Repository:
远程仓库(私服):一般由公司团队搭建的私有仓库。

3、Maven安装
(1)解压Apache-maven-3.9.4-bin.zip
(2)配置本地仓库
解压Maven文件,创建mvn-repo文件夹,并在conf\settings.xml文件下构建此本地仓库路径

(3)配置阿里云私服地址
该文件中<mirrors>标签中覆盖粘贴
XML
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
(4)配置环境变量

path中

(5)测试

二、IDEA集成Maven
1、Maven项目创建
(1)配置Maven和JDK
在欢迎页面
配置Maven


配置JRE

配置字节码文件

配置JDK版本,在新建的项目里面打开Project Settings
JDK和语言版本都选21(教程里面选的17)

(2)创建模块


这就是创建出来的Maven项目

Maven项目文件介绍

2、Maven坐标
什么是坐标?
Maven中的坐标是资源(jar)的唯一标识,通过该坐标可以唯一定位资源位置。
使用坐标来定义项目或引入项目中需要的依赖。
Maven坐标主要组成
-
groupld:定义当前Maven项目隶属组织名称(通常是域名反写,例如:com.itheima)
-
artifactld:定义当前Maven项目名称(通常是模块名称,例如order-service、goods-service)
-
version:定义当前项目版本号
-
SNAPSHOT:功能不稳定、尚处于开发中的版本,即快照版本
-
RELEASE:功能趋于稳定、当前更新停止,可以用于发行的版本
-
上面两个都是约定 而不是规定
-
例如:
XML
<groupld>com.itheima</groupld>
<artifactld>maven-project01</artifactld>
<version>1.0-SNAPSHOT</version>
3、Maven项目导入
(1)方式一

(2)方式二

(3)演示
先将Maven项目放到项目文件夹下面

选择这个pom文件

先导入项目获取项目,再导入项目识别Maven项目
导入Maven项目
建议将要导入的maven项目复制到你的项目目录下
建议选择maven项目的pom.xml文件进行导入
因为会将关联项目一并导入
三、依赖管理
1、依赖配置
依赖:指当前项目运行 所需要的jar包,一个项目中可以引入多个依赖。
配置: 1.在pom.xml中编写<dependencies>标签
2.在<dependencies>标签中使用<dependency>引入坐标
3.定义坐标的groupld,artifactld,version
4.点击刷新按钮,引入最新加入的坐标
注意: 如果不知道依赖的坐标信息,可以到https://mvnrepository.com/中搜索。
当引入依赖时,会引入多个依赖,这些依赖都是引入该依赖时的依赖的其他依赖,称为Maven的依赖传递

如果不想要某个依赖,可以排除依赖
排除依赖:指主动断开依赖的资源,被排除的资源无需指定版本。

2、生命周期
Maven的生命周期就是为了对所有的maven项目构建过程进行抽象和统一。
Maven中有3套相互独立的生命周期:
clean:清理工作。
default:核心工作,如:编译、测试、打包、安装、部署等。
site:生成报告、发布站点等。
每套生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。
Maven生命周期的各个阶段

主要了解五个阶段
生命周期阶段
clean:移除上一次构建生成的文件
compile:编译项目源代码
test:使用合适的单元测试框架运行测试(junit)
package:将编译后的文件打包,如:jar、war等
install:安装项目到本地仓库

注意: 在同一套生命周期中,当运行后面的阶段时,前面的阶段都会运行。
clean就和其他四个不在同一套生命周期中
演示:在Maven项目下cmd,输入mvn clean、mvn compile等,在命令行窗口运行Maven生命周期
install了Maven项目之后,会在本地仓库下创建Maven项目的jar包,具体路径可以顺着xml文件找
重新看这张图

四、单元测试
1、概述
测试:是一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。
(1)阶段划分
单元测试、集成测试、系统测试、验收测试。
单元测试
介绍:对软件的基本组成单位进行测试,最小测试单位。
目的:检验软件基本组成单位 的正确性。
测试人员:开发人员
集成测试
介绍:将已分别 通过测试的单元 ,按设计要求组合成系统或子系统,再进行的测试。
目的:检查单元之间的协作是否正确。
测试人员:开发人员
系统测试
介绍:对已经集成好的软件系统进行彻底的测试。
目的:验证软件系统的正确性、性能是否满足指定的要求。
测试人员:测试人员
验收测试
介绍:交付测试,是针对用户需求、业务流程进行的正式的测试。
目的:验证软件系统是否满足验收标准。
测试人员:客户/需求方
(2)测试方法




2、入门
(1)main方法测试
-
测试代码与源代码未分开,难维护
-
一个方法测试失败,影响后面方法
-
无法自动化测试,得到测试报告
(3)JUnit单元测试(推荐)
-
测试代码与源代码分开,便于维护
-
可根据需要进行自动化测试
-
可自动分析测试结果,产出测试报告
(4)案例
使用JUnit,对UserService中业务方法进行单元测试。
1.在pom.xml中,引入JUnit的依赖。
XML
<!--junit依赖-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.1</version>
<!--依赖范围-->
<scope>test</scope>
</dependency>
2.在test\java目录下,创建测试类,并编写对应的测试方法,并在方法上声明@Test注解。
注意:
JUnit单元测试类名命名规范为:XxxxxTest【规范】。
JUnit单元测试的方法,必须声明为public void【规定】
java
package com.itheima;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
/**
* 测试类
*/
@DisplayName("用户信息测试类")
public class UserServiceTest {
@Test
public void testGetAge(){
//先new一个对象
UserService userService = new UserService();
Integer age = userService.getAge("100000200010011011");
System.out.println(age);
}
}
3.运行单元测试(测试通过:绿色;测试失败:红色)。

3、断言
(1)断言方法
JUnit提供了一些辅助方法 ,用来帮我们确定被测试的方法是否按照预期的效果正常工作,这种方式称为断言。
java
exp代表期望值,act代表实际值
Assertions.assertEquals(Object exp,Object act,String msg)//检查两个值是否相等,不相等就报错。
Assertions.assertNotEquals(Object unexp,Object act,String msg)//检查两个值是否不相等,相等就报错。
Assertions.assertNull(Object act, String msg)//检查对象是否为null,不为null,就报错。
Assertions.assertNotNull(Object act,String msg)//检查对象是否不为null,为null,就报错。
Assertions.assertTrue(boolean condition, String msg)//检查条件是否为true,不为true,就报错。
Assertions.assertFalse(boolean condition, String msg)//检查条件是否为false,不为false,就报错。
Assertions.assertThrows(Class expType,Executable exec,String msg)//检查程序运行抛出的异常,是否符合预期
//Executable代表函数式接口
提示:
上述方法形参中的最后一个参数msg,表示错误提示信息,可以不指定(有对应的重载方法)。
(2)案例:检查两个值是否相等
身份证倒数第二位是奇数代表男性,偶数代表女性
java
/**
* 断言
*/
@Test
public void testGenderWithAssert(){
UserService userService = new UserService();
String gender = userService.getGender("100000200010011011");
//断言
//Assertions.assertEquals("男", gender);
Assertions.assertEquals("男", gender, "性别获取错误有问题");
}
若断言测试失败

(3)案例:检查程序运行抛出的异常
参数传入异常类型和一个Lambda表达式
java
/**
* 断言
*/
@Test
public void testGenderWithAssert2(){
UserService userService = new UserService();
//断言
Assertions.assertThrows(IllegalArgumentException.class, () -> {
userService.getGender(null);
});
}
异常类型:业务逻辑中抛出的异常,身份证号码无效
Lambda表达式中调用该方法,传入参数为null
java
public String getGender(String idCard){
if (idCard == null || idCard.length() != 18) {
throw new IllegalArgumentException("无效的身份证号码");
}
return Integer.parseInt(idCard.substring(16,17)) % 2 == 1 ? "男" : "女";
}
若未抛出异常,则显示未抛出异常的失败断言

4、常见注解
(1)常见注解
在JUnit中还提供了一些注解,还增强其功能,常见的注解有以下几个:
java
注解
说明
备注
@Test
测试类中的方法用它修饰才能成为测试方法,才能启动执行
单元测试
@ParameterizedTest
参数化测试的注解(可以让单个测试运行多次,每次运行时仅参数不同)
用了该注解,就不需要@Test注解了
@ValueSource
参数化测试的参数来源,赋予测试方法参数
与参数化测试注解配合使用
@DisplayName
指定测试类、测试方法显示的名称(默认为类名、方法名)
@BeforeEach
用来修饰一个**实例方法**,该方法会在**每一个**测试方法执行之前执行一次。
初始化资源(准备工作)
@AfterEach
用来修饰一个**实例方法**,该方法会在**每一个**测试方法执行之后执行一次。
释放资源(清理工作)
@BeforeAll
用来修饰一个**静态方法**,该方法会在所有测试方法之前**只执行一次**。
初始化资源(准备工作)
@AfterAll
用来修饰一个**静态方法**,该方法会在所有测试方法之后**只执行一次**。
释放资源(清理工作)
(2)@BeforeEach、@AfterEach、@BeforeAll、@AfterAll的使用
可以用于new业务的方法
java
@BeforeAll //在所有的单元测试方法运行之前, 运行一次
public static void beforeAll(){
System.out.println("before All");
}
@AfterAll //在所有的单元测试方法运行之后, 运行一次
public static void afterAll(){
System.out.println("after All");
}
@BeforeEach //在每一个单元测试方法运行之前, 都会运行一次
public void beforeEach(){
System.out.println("before Each");
}
@AfterEach //在每一个单元测试方法运行之后, 都会运行一次
public void afterEach(){
System.out.println("after Each");
}
(3)参数化测试
java
/**
* 参数化测试
*/
@DisplayName("测试用户性别")
@ParameterizedTest
@ValueSource(strings = {"100000200010011011","100000200010011031","100000200010011051"})
public void testGetGender2(String idCard){
UserService userService = new UserService();
String gender = userService.getGender(idCard);
//断言
Assertions.assertEquals("男", gender);
}
控制台输出结果

5、企业开发单元测试定义规范
(1)测试注意
要考虑边界情况和正常情况
新创建多个单元测试方法
(2)查看单元测试的覆盖率

在右侧展示单元测试覆盖率

Class:类的覆盖率
Method:方法的覆盖率(getGender方法测试到了,但是getAge方法没有测试到)
Line:代码有多少覆盖到了
Branch:分支(if else)
(3)只测单个文件的单元测试覆盖率


6、基于AI依赖自动生成单元测试2
在业务方法上面的通义灵码中,使用AI生成单元测试

7、Maven依赖范围
(1)依赖作用范围
在maven项目中,test目录存放单元测试的代码,是否可以在main目录中编写单元测试呢?

依赖的jar包,默认情况下,可以在任何地方使用。可以通过<scope>...</scope>设置其作用范围。
作用范围:
主程序范围有效。(main文件夹范围内)
测试程序范围有效。(test文件夹范围内)
是否参与打包运行。(package指令范围内)
作用范围:

因此,junit依赖可以限制作用范围
XML
<!--junit依赖-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.1</version>
<!--依赖范围-->
<!--默认是comple-->
<scope>test</scope>
</dependency>
(2)maven的生命周期,test详解
当生命周期执行到test时,所有命名规范的(以Test为结尾的)测试方法都会运行
若已经执行过test,不想重复执行,可以点击这里跳过test

五、Maven常见问题解决方案
Maven文件未完成下载
产生原因:由于网络原因,依赖没有下载完整导致的,在maven仓库中生成了xxx.lastUpdated文件,该文件不删除,不会再重新下载。

解决方案: 1.根据maven依赖的坐标,找到仓库中对应的xxx.lastUpdated文件,删除,删除之后重新加载项目即可。

2.通过命令(del/s*.lastUpdated)批量递归删除指定目录下的xxx.lastUpdated文件,删除之后重新加载项目即可。
在Maven仓库的根目录下cmd执行del/s*.lastUpdated
3.双击Maven目录下的del.bat文件,该文件打包好了cmd命令
最后重启项目即可
注意: 重新加载依赖,依赖下载了之后,maven面板可能还会报红,此时可以关闭IDEA,重新打开IDEA加载此项目即可。