【JavaWeb】Maven(下)

1 依赖管理

1.1 依赖配置

1.1.1 基本配置

依赖:指当前项目运行所需要的jar包。

一个项目中可以引入多个依赖:

例如:在当前工程中,我们需要用到logback来记录日志,此时就可以在maven工程的pom.xml文件中,引入logback的依赖。具体步骤如下:

1. 在pom.xml中编写<dependencies>标签

2. 在<dependencies>标签中使用<dependency>引入坐标

3. 定义坐标的 groupId、artifactId、version

4. 点击刷新按钮,引入最新加入的坐标

<dependencies>
    <!-- 依赖 : spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.1.4</version>
    </dependency>
</dependencies>

注:如果引入的依赖在本地仓库中不存在,将会连接远程仓库 / 中央仓库后下载依赖(比较耗时) 若不知道依赖的坐标信息,可以到mvn的中央仓库(https://mvnrepository.com/)中搜索

1.1.2 依赖传递

我们上面在pom.xml中配置了一项依赖,即spring-context,但通过右侧的maven面板可以看到,其实引入进来的依赖并不止这一项,有很多的依赖都引入进来了。如下图所示:

为何出现这样的现象呢? 这里涉及到maven中很重要的一个特性,即Maven中的依赖传递

所谓maven的依赖传递,是指如果在maven项目中,A 依赖了B,B依赖了C,C依赖了D,那么在A项目中也会有C、D依赖,因为依赖会传递。  

如果传递下来的依赖在项目开发中我们不需要,可通过Maven中的排除依赖功能,来将这个依赖排除掉。

1.1.3 排除依赖

排除依赖:指主动断开依赖的资源,被排除的资源无需指定版本

配置形式如下:

<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>

1.2 生命周期

1.2.1 介绍

Maven的生命周期就是为了对所有的构建过程进行抽象和统一。 描述了一次项目构建,经历哪些阶段。

在Maven出现之前,项目构建的生命周期就已经存在,软件开发人员每天都在对项目进行清理,编译,测试及部署。虽然大家都在不停地做构建工作,但公司和公司间、项目和项目间,往往使用不同的方式做类似的工作。

Maven从大量项目和构建工具中学习和反思,然后总结了一套高度完美的,易扩展的项目构建生命周期。这个生命周期包含了项目的清理,初始化,编译,测试,打包,集成测试,验证,部署和站点生成等几乎所有构建步骤。

Maven对项目构建的生命周期划分为3套(相互独立):

- clean:清理工作。

- default:核心工作。如:编译、测试、打包、安装、部署等。

- site:生成报告、发布站点等。

三个周期又包含许多具体阶段,其中我们主要了解五个阶段:

- clean:移除上一次构建生成的文件

- compile:编译项目源代码

- test:使用合适的单元测试框架运行测试(junit)

- package:将编译后的文件打包,如:jar、war等

- install:安装项目到本地仓库

IDEA工具为了方便程序员使用maven生命周期,在右侧的maven工具栏中给出了快速访问通道。

说明:在同一套生命周期中,我们在执行后面的生命周期时,前面的生命周期都会执行。

1.2.2 执行

在日常开发中,当我们要执行指定的生命周期时,有两种执行方式

1. 在idea工具右侧的maven工具栏中,选择对应的生命周期,双击执行

2. 在DOS命令行中,通过maven命令执行

方式一:选择对应的生命周期,双击执行

以clean为例:

编译后,clean前:

clean后:

方式二:在命令行中执行生命周期

1.打开maven项目对应的磁盘目录

2.在当前目录下打开CMD

3.输入 mvn clean  回车运行

   同理,我们也可以在命令执行:

   mvn compile

   mvn test

   mvn package

   mvn install

2 单元测试

2.1 介绍

测试:是一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。

阶段划分:单元测试、集成测试、系统测试、验收测试。

1) 单元测试

  • 介绍:对软件的基本组成单位进行测试,最小测试单位。

  • 目的:检验软件基本组成单位的正确性。

  • 测试人员:开发人员

2) 集成测试

  • 介绍:将已分别通过测试的单元,按设计要求组合成系统或子系统,再进行的测试。

  • 目的:检查单元之间的协作是否正确。

  • 测试人员:开发人员

3) 系统测试

  • 介绍:对已经集成好的软件系统进行彻底的测试。

  • 目的:验证软件系统的正确性、性能是否满足指定的要求。

  • 测试人员:测试人员

4) 验收测试

  • 介绍:交付测试,是针对用户需求、业务流程进行的正式的测试。

  • 目的:验证软件系统是否满足验收标准。

  • 测试人员:客户/需求方

测试方法:白盒测试、黑盒测试 及 灰盒测试。

1) 白盒测试

清楚软件内部结构、代码逻辑。

用于验证代码、逻辑正确性。

2) 黑盒测试

不清楚软件内部结构、代码逻辑。

用于验证软件的功能、兼容性、验收测试等方面。

3) 灰盒测试

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

2.2 Junit入门

2.2.1 单元测试

单元测试:就是针对最小的功能单元(方法),编写测试代码对其正确性进行测试。

Junit:最流行的Java测试框架之一,提供了一些功能,方便程序进行单元测试(第三方公司提供)。

之前我们进行程序的测试 都是main方法中进行,但在main方法进行测试时会存在如下问题:

1. 测试代码与源代码未分开,难维护。

2. 一个方法测试失败,影响后面方法。

3. 无法自动化测试,得到测试报告。

而如果我们使用了Junit单元测试框架进行测试,将会有以下优势:

1. 测试代码与源代码分开,便于维护。

2. 可根据需要进行自动化测试。

3. 可自动分析测试结果,产出测试报告。

2.2.2 入门程序

1. 在pom.xml中,引入JUnit的依赖,如下。

2. 在test/java目录下,创建测试类,并编写对应的测试方法,并在方法上声明@Test注解。

3. 运行单元测试 (测试通过:绿色测试失败:红色)。

<!--Junit单元测试依赖-->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.9.1</version>
    <scope>test</scope>
</dependency>

例如在主程序中引入UserService类:

import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;

public class UserService {

    /**
     * 给定一个身份证号, 计算出该用户的年龄
     * @param idCard 身份证号
     */
    public Integer getAge(String idCard){
        if (idCard == null || idCard.length() != 18) {
            throw new IllegalArgumentException("无效的身份证号码");
        }
        String birthday = idCard.substring(6, 14);
        LocalDate parse = LocalDate.parse(birthday, DateTimeFormatter.ofPattern("yyyyMMdd"));
        return Period.between(parse, LocalDate.now()).getYears();
    }

    /**
     * 给定一个身份证号, 计算出该用户的性别
     * @param idCard 身份证号
     */
    public String getGender(String idCard){
        if (idCard == null || idCard.length() != 18) {
            throw new IllegalArgumentException("无效的身份证号码");
        }
        return Integer.parseInt(idCard.substring(16,17)) % 2 == 1 ? "男" : "女";
    }
}

 在测试类中进行测试代码的编写,例如:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class UserServiceTest {

    @Test
    public void testGetaAge(){
        UserService userService = new UserService();
        Integer age = userService.getAge("100000200010011011");
        System.out.println(age);
    }

    @Test
    public void testGetGenderWithAssert(){
        UserService userService = new UserService();
        String gender = userService.getGender("100000200110011011");
        Assertions.assertEquals("男", gender,"性别获取逻辑有问题");
    }
}

注:

测试类的命名规范为:XxxxTest

测试方法的命名规定为:public void xxx(){...}

2.3 断言

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

断言方法描述
assertEquals(Object exp, Object act, String msg)检查两个值是否相等,不相等就报错。
assertNotEquals(Object unexp, Object act, String msg)检查两个值是否不相等,相等就报错。
assertNull(Object act, String msg)检查对象是否为null,不为null,就报错。
assertNotNull(Object act, String msg)检查对象是否不为null,为null,就报错。
assertTrue(boolean condition, String msg)检查条件是否为true,不为true,就报错。
assertFalse(boolean condition, String msg)检查条件是否为false,不为false,就报错。
assertSame(Object exp, Object act, String msg)检查两个对象引用是否相等,不相等,就报错。

2.4 常见注解

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

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

演示 @BeforeEach,@AfterEach,@BeforeAll,@AfterAll 注解:

public class UserServiceTest {

    @BeforeEach
    public void testBefore(){
        System.out.println("before...");
    }

    @AfterEach
    public void testAfter(){
        System.out.println("after...");
    }

    @BeforeAll //该方法必须被static修饰
    public static void testBeforeAll(){ 
        System.out.println("before all ...");
    }

    @AfterAll //该方法必须被static修饰
    public static void testAfterAll(){
        System.out.println("after all...");
    }

    @Test
    public void testGetAge(){
        Integer age = new UserService().getAge("110002200505091218");
        System.out.println(age);
    }
    
    @Test
    public void testGetGender(){
        String gender = new UserService().getGender("612429198904201611");
        System.out.println(gender);
    }
 }   

输出结果:

 演示 @ParameterizedTest  ,@ValueSource ,@DisplayName 注解:

import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

@DisplayName("测试-学生业务操作")
public class UserServiceTest {

    @DisplayName("测试-获取年龄")
    @Test
    public void testGetAge(){
        Integer age = new UserService().getAge("110002200505091218");
        System.out.println(age);
    }

    @DisplayName("测试-获取性别")
    @Test
    public void testGetGender(){
        String gender = new UserService().getGender("612429198904201611");
        System.out.println(gender);
    }

    @DisplayName("测试-获取性别3")
    @ParameterizedTest
    @ValueSource(strings = {"612429198904201611","612429198904201631","612429198904201626"})
    public void testGetGender3(String idcard){
        String gender = new UserService().getGender(idcard);
         System.out.println(gender);
    }
}

输出结果:

注:在maven项目中,test目录存放单元测试的代码,是否可以在main目录中编写单元测试呢 ? 可以,但是不规范

2.5 依赖范围

依赖的jar包,默认情况下可以在任何地方使用:在main目录下,可以使用;在test目录下,也可以使用。  

在maven中,如果希望限制依赖的使用范围,可以通过 <scope>…</scope> 设置其作用范围。

作用范围:

主程序范围有效。(main文件夹范围内)

测试程序范围有效。(test文件夹范围内)

是否参与打包运行。(package指令范围内)

如果对Junit单元测试的依赖,设置了scope为 test,就代表该依赖只在测试程序中可以使用,在主程序中是无法使用的

例如:

<!--junit依赖-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.9.1</version>
            <scope>test</scope>
        </dependency>

注:更改pom文件后记得点击更新 

scope的取值常见的如下:

scope值主程序测试程序打包(运行)范例
compile(默认)YYYlog4j
test-Y-junit
providedYY-servlet-api
runtime-YYjdbc驱动

3 Maven常见问题

问题现象:Maven项目中添加的依赖,未正确下载,造成右侧Maven面板中的依赖报红,再次reload重新加载也不会再下载。

产生原因:由于网络原因,依赖没有下载完整导致的,在maven仓库中生成了xxx.lastUpdated文件,该文件不删除,不会再重新下载。

解决方案:

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

2. 更快速的方法:在maven安装包目录下进入控制台,通过命令 (del /s *.lastUpdated) 批量递归删除指定目录下的 xxx.lastUpdated 文件,删除之后重新加载项目即可。

3. 重新加载依赖,依赖下载了之后,maven面板可能还会报红,此时可以关闭IDEA,重新打开IDEA加载此项目即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值