运行DEMO可以在百度网盘中获取:通过网盘分享的文件:https://pan.baidu.com/s/1Ut9-STQL_8ColkAa4-kMkQ?pwd=edar

Maven

Apache Maven是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建

官网:http://maven.apache.org

作用

  1. 方便快捷的管理项目依赖的资源(jar包),避免版本冲突问题
  2. 提供标准、统一的项目结构
  3. 标准跨平台(Linux、Windows、MacOS)的自动化项目构建方式

仓库

用于存储资源,管理各种jar包

  • 本地仓库:存放在自己计算机上的目录
  • 中央仓库:由Maven团队维护的全球唯一的仓库。仓库地址:https://repo1.maven.org/maven2/
  • 远程仓库(私服):一般由公司团队搭建的私有仓库

安装

安装步骤:

  1. 解压apache-maven-x.x.x-bin.zip

  2. 配置本地仓库:修改conf/setting.xml中的<localRepository>为一个指定目录

    1
    <localRepository>E:\develop\apache-maven-x.x.x\mvn-reop</localRepository>
  3. 配置阿里云私服:修改conf/setting.xml中的<mirrors>标签,为其添加如下子标签:

    1
    2
    3
    4
    5
    6
    <mirror>
    <id>alimaven</id>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <mirrorOf>central</mirrorOf>
    </mirror>
  4. 配置环境变量:MAVEN_HOME为maven的解压目录,并将其bin目录加入PATH环境变量

配置Maven环境

当前工程

  • 选中IDEA中File➡Setting➡Build,Execution,Deployment➡Build Tools➡Maven
  • 设置IDEA使用本地安装的Maven,并修改配置本地文件及本地仓库路径
  • 设置Runner中的JDK版本
  • 设置字节码版本File➡Setting➡Build,Execution,Deployment➡Complier➡Java Compiler➡project bytecode version

全局工程

  1. 首先需要退出项目File➡close project
  2. 进入IDEA开始界面
  3. 找到Customize➡All settings
  4. 重复当前工程的操作

创建Maven项目

  1. 创建模块,选择Maven,点击Next
  2. 填写模块名称,坐标信息,点击Finish,创建完成

当创建完成后,编写Hello World测试环境配置是否成功

如果编译后出现java: 错误: 不支持发行版本 6报错信息,则需要找到当前项目的pom.xml文件,添加如下代码

1
2
3
4
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

17表示JDK版本

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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.norlcyan</groupId>
<artifactId>test01</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

</project>

注意:修改完代码,需要在IDEA中重新加载配置文件,IDEA会在右上角出现一个M的标志,点击即可

Maven坐标

  • Maven中的坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置
  • 使用坐标来定义项目或引入项目中需要的依赖

坐标的组成

  1. groupId:定义当前Maven项目隶属组织名称(通常是域名反写,例如:app.netlify.norlcyan)
  2. artifactId:定义当前Maven项目名称(通常是模块名称,例如:order-service、goods-service)
  3. version:定义当前项目的版本号
1
2
3
<groupId>app.netlify.norlcyan</groupId>
<artifactId>test01</artifactId>
<version>1.0-SNAPSHOT</version>
1
2
3
4
5
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>

依赖管理

  • 依赖:指当前项目运行所需要的jar包,一个项目中可以引入多个依赖
  • 配置:
    1. pom.xml中编写<dependencies>标签
    2. 在<dependencies>标签中使用<dependency>引入坐标
    3. 定义坐标的groupId、artifactId、version
    4. 点击刷新按钮,引入最新的坐标

注意:

  1. 如果本地仓库中没有依赖的jar包,代码不会提示,且pom.xml文件会报红,当填写完依赖包的详细信息后,点击刷新会自动下载缺少的包
  2. 要想知道依赖包的详细信息,可以访问https://mvnrepository.com/查看

依赖传递

  • Maven中的依赖具有传递性
    • 直接依赖:在当前项目中通过依赖配置建立的依赖关系
    • 间接依赖:被依赖的资源如果依赖其他资源,当前项目间接依赖其他资源

依赖范围

依赖的jar包,默认情况下,可以在任何地方使用。可以通过<scope>…</scope>设置其作用的范围

作用范围:

  • 主程序范围有效(main文件夹范围内)
  • 测试程序范围有效(test文件夹范围内)
  • 是否参与打包运行(package指令范围内)
scope值 主程序 测试程序 打包 范例
compile(默认) Y Y Y log4j
test - Y - junit
provided Y Y - servlet-api
runtime - Y Y jdbc驱动

示例:

1
2
3
4
5
6
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>

生命周期

Maven的生命周期就是为了所有的maven项目构建过程进行抽象和统一

Maven有三套相互独立的生命周期:

  • clean:清理工作
  • default:核心工作,如:编译、测试、打包、安装、部署等
  • site:生成报告、发布站点等

生命周期阶段:

  • clean:移除上一次构建生成的文件
  • complie:编译项目源代码
  • test:使用合适的单元测试框架进行测试(junit)
  • package:将编译后的文件打包,如:jar、war等
  • install:安装项目到本地仓库

测试

  • 测试:是一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程
  • 阶段划分:单元测试、集成测试、系统测试、验收测试
  • 测试方法:白盒测试、黑盒测试以及灰盒测试

白盒测试:

  • 清楚软件内部结构、代码逻辑
  • 用于验证代码、逻辑正确性

黑盒测试:

  • 不清楚软件内部结构、代码逻辑
  • 用于验证软件的功能、兼容性等方面

灰盒测试:

  • 结合了白盒测试和黑盒测试的特点,既关注软件的内部结构又考虑外部表现(功能)

单元测试:

  • 介绍:对软件的基本组成单位进行测试,最小测试单位
  • 目的:检验软件基本组成单位的正确性
  • 测试人员:开发人员
  • 白盒测试

集成测试:

  • 将已分别通过测试的单元,按设计要求组合成系统或子系统,再进行的测试
  • 目的:检查单元之间的协作是否正确
  • 测试人员:开发人员
  • 灰盒测试

系统测试:

  • 介绍:对已经继承好的软件系统进行彻底的测试
  • 目的:验证软件系统的正确性、性能是否满足指定的要求
  • 测试人员:测试人员
  • 黑盒测试

验收测试:

  • 介绍:交付测试,是针对用户需求、业务流程进行的正式的测试
  • 目的:验证软件系统是否满足验收标准
  • 测试人员:客户/需求方
  • 黑盒测试

单元测试

  • 单元测试就是针对最小的功能单元(方法),编写测试代对其正确性进行测试
  • Junit是最流行的Java测试框架之一,提供了一些功能,方便程序进行单元测试(第三方公司提供)
  • main方法测试的弊端:
    • 测试代码与源代码未分开,难以维护
    • 一个方法测试失败,影响后面方法的运行
    • 无法自动化测试,得到测试报告

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Test {
public static void main(String[] args) {
// 查询所有的测试方法
findALLStudent();
// 添加学生
addStudent();
// 修改学生
updateStudent();
// 删除学生
deleteStudent();
}
// 测试删除学生
private static void deleteStudent() {...}
// 测试修改学生
private static void updateStudent() {...}
// 测试添加学生的方法
private static void addStudent() {...}
// 查询所有的学生数据
private static void findALLStudent() {...}
}

JUnit

初次使用JUnit

  1. 在pom.xml中,引入JUnit的依赖:
1
2
3
4
5
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.1</version>
</dependency>
  1. 在test/java目录下,创建测试类,并编写对应的测试方法,并在方法上声明@Test注解
1
2
3
4
5
@Test
public void testGetAge() {
Integer age = new UserSerive().getAge("110002200505091218")
System.out.println(age)
}

注意:JUnit单元测试类名命名规范为XxxxTest【规范】。Junit单元测试的方法,必须声明为public void 【规定】

  1. 运行单元测试(测试通过:绿色;测试失败:红色)
1
2
3
4
5
6
7
8
9
10
11
12
package app.netlify.norlcyan;

import org.junit.jupiter.api.Test;

public class UserServiceTest {
@Test
public void testGetAge() {
UserService userService = new UserService();
Integer age = userService.getAge("110002200505091218");
System.out.println(age);
}
}

断言

JUnit提供了一些辅助方法,用来确定被测试方法是否按照预期的效果正常工作,这种方式称为断言

断言方法 描述
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) 检查两个对象引用是否相等,不相等报错

示例:

1
2
3
4
5
6
7
@Test
public void testGenderWithAssert() {
UserService userService = new UserService();
String gender = userService.getGender("100000200010011011");
// 断言
Assertions.assertEquals("男",gender);
}

常见注解

在JUnit中还提供了一些注解,还增强其功能,常见的注解有以下几个:

注解 说明 备注
@Test 测试类中的方法用它修饰才能成为测试方法,才能启动执行 单元测试
ParameterizedTest 参数化测试的注解(可以让单个测试运行多次,每次运行时仅参数不同) 用了该注解就不需要@Test注解了
@ValueSource 参数化测试的参数来源,赋予测试方法参数 与参数化测试注解配合使用
@DisplayName 指定测试类、测试方法显示的名称(默认为类名、方法名)
@BeforeEach 用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次 初始化资源(准备工作)
@AfterEach 用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次 释放资源(清理工作)
@BeforeAll 用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次 初始化资源(准备工作)
@AfterAll 用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次 释放资源(清理工作)

示例:

1
2
3
4
5
6
7
8
9
@DisplayName("测试性别")    // 控制台会显示该测试的名称为”测试性别“
@ParameterizedTest
@ValueSource(strings = {"100000200010011011","100000200010011041","100000200010011051"})
public void testGender2(String idCard) {
UserService userService = new UserService();
String gender = userService.getGender(idCard);
// 断言
Assertions.assertEquals("男",gender); // 测试三次,第二次是错误结果
}

企业开发规范

原则:编写测试方法时,要尽可能的覆盖业务方法中所有可能的情况(尤其是边界值)

实际开发中,有可能会编写大量的单元测试,难免出现缺漏某些情况。为了防止出现这种情况,可以借助AI生产测试代码。

在IDEA插件中安装通义灵码,并且登录账户(免费)。然后在需要测试的代码上点击生成单元测试即可。