Java工程基础_单元测试_配置文件_JavaBean

O泡李华 9

Java 工程基础:单元测试 + 配置文件 + JavaBean

本章位置:第二阶段 Java 核心框架
前置知识:JavaSE 基础、面向对象、异常、集合、IO、Maven
本章内容:JUnit 单元测试、配置文件、JavaBean
下一篇:单例、匿名内部类、枚举
学习目标:学会把 Java 代码从“能运行”逐步写成“方便测试、方便配置、方便维护”的工程代码。


一、为什么第二阶段先学这三个知识

第一阶段我们更多是在写:

public static void main(String[] args) {

}

然后通过:

运行 main 方法

测试代码。

进入第二阶段以后,项目会越来越大。

例如:

MyBatis
Servlet
SpringBoot
RBAC
业务项目

这时候会出现三个非常现实的问题:

1. 一个方法到底对不对,难道每次都运行整个项目?

2. 数据库地址、用户名、密码难道全部写死在 Java 代码里?

3. Java 对象怎样写才能让框架更容易创建、读取和修改?

对应解决方案就是:

单元测试
配置文件
JavaBean

第一部分:单元测试

二、什么是单元测试

单元测试:

Unit Test

可以理解为:

针对程序中某一个较小的功能单元进行自动测试。

这个“单元”通常可以是:

一个方法
一个类
一个业务功能

例如有:

public int add(
        int a,
        int b
) {

    return a + b;
}

我们希望自动确认:

add(1, 2)
是不是等于 3

这就是一个很典型的单元测试。


三、为什么不能一直靠 main 方法测试

假设:

public static void main(
        String[] args
) {

    Calculator calculator =
            new Calculator();

    System.out.println(
            calculator.add(
                    1,
                    2
            )
    );
}

然后自己看控制台:

3

这种方式的问题:

需要人工观察结果

测试代码和业务代码容易混在一起

测试数量多后非常混乱

很难一次执行全部测试

修改代码后不容易知道哪里被影响

所以项目开发会使用:

JUnit

四、JUnit 是什么

JUnit 是 Java 中非常经典的:

单元测试框架

当前 Java 项目中通常使用:

JUnit 5

JUnit 5 中最常见:

@Test

以及:

Assertions

五、Maven 项目引入 JUnit 5

在:

pom.xml

中加入:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.11.4</version>
    <scope>test</scope>
</dependency>

其中:

<scope>test</scope>

表示:

主要只在测试阶段使用

不会作为普通业务依赖使用。


六、标准 Maven 测试目录

正常 Maven 项目:

src
├─ main
│  ├─ java
│  └─ resources
│
└─ test
   ├─ java
   └─ resources

业务代码:

src/main/java

测试代码:

src/test/java

七、为什么测试代码单独放

这样可以:

业务代码和测试代码分离

测试依赖只在测试阶段使用

Maven 可以自动识别测试目录

IDEA 可以直接运行测试

八、第一个被测试类

创建:

Calculator.java
package com.example;

public class Calculator {

    public int add(
            int a,
            int b
    ) {

        return a + b;
    }

    public int subtract(
            int a,
            int b
    ) {

        return a - b;
    }
}

九、第一个 JUnit 测试

在:

src/test/java

创建:

CalculatorTest.java
package com.example;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class CalculatorTest {

    @Test
    void testAdd() {

        Calculator calculator =
                new Calculator();

        int result =
                calculator.add(
                        1,
                        2
                );

        assertEquals(
                3,
                result
        );
    }
}

十、@Test

@Test

表示:

这个方法是测试方法

JUnit 会识别它并执行。


十一、assertEquals()

assertEquals(
        3,
        result
);

意思:

我期望 result 等于 3

如果:

实际值 == 期望值

测试通过。

否则:

测试失败

十二、测试不是“打印结果”

错误思路:

System.out.println(
        result
);

然后人工判断。

真正的自动测试应该使用:

断言
Assertion

让程序自己判断:

通过
失败

十三、常见断言

assertEquals

assertEquals(
        expected,
        actual
);

比较:

期望值和实际值

assertNotEquals

assertNotEquals(
        10,
        result
);

assertTrue

assertTrue(
        age >= 18
);

assertFalse

assertFalse(
        list.isEmpty()
);

assertNull

assertNull(
        result
);

assertNotNull

assertNotNull(
        user
);

assertSame

assertSame(
        object1,
        object2
);

判断:

两个引用是不是同一个对象

这和:

equals()

不是一回事。


十四、测试异常 assertThrows

假设:

public int divide(
        int a,
        int b
) {

    if (b == 0) {

        throw new IllegalArgumentException(
                "除数不能为 0"
        );
    }

    return a / b;
}

测试:

@Test
void testDivideByZero() {

    Calculator calculator =
            new Calculator();

    assertThrows(
            IllegalArgumentException.class,
            () ->
                    calculator.divide(
                            10,
                            0
                    )
    );
}

十五、测试方法命名

可以写:

testAdd()

也可以写得更清楚:

add_shouldReturn3_when1Plus2()

现代项目越来越推荐:

测试名称能表达场景和预期

例如:

given
when
then

思路。


十六、@BeforeEach

如果每个测试都要:

new Calculator()

可以:

@BeforeEach
void setUp() {

    calculator =
            new Calculator();
}

例如:

public class CalculatorTest {

    private Calculator calculator;

    @BeforeEach
    void setUp() {

        calculator =
                new Calculator();
    }

    @Test
    void testAdd() {

        assertEquals(
                3,
                calculator.add(
                        1,
                        2
                )
        );
    }
}

十七、@AfterEach

每个测试结束后执行:

@AfterEach
void tearDown() {

}

常用于:

清理测试数据

释放测试资源

十八、@BeforeAll

整个测试类开始前:

只执行一次

例如:

@BeforeAll
static void init() {

}

十九、@AfterAll

整个测试类结束后:

只执行一次
@AfterAll
static void destroy() {

}

二十、常用生命周期顺序

可以理解:

@BeforeAll
↓
@BeforeEach
↓
@Test
↓
@AfterEach
↓
@BeforeEach
↓
@Test
↓
@AfterEach
↓
@AfterAll

二十一、@DisplayName

可以给测试显示中文名称:

@Test
@DisplayName(
        "1 + 2 应该等于 3"
)
void testAdd() {

}

二十二、@Disabled

暂时禁用测试:

@Disabled
@Test
void testSomething() {

}

一般用于:

暂时无法运行
尚未完成
环境暂时不满足

不要为了让项目“全绿”就随便禁用失败测试。


二十三、参数化测试简单了解

如果要测试:

1 + 2 = 3

2 + 3 = 5

5 + 5 = 10

不一定写三个方法。

JUnit 支持:

参数化测试

例如:

@ParameterizedTest
@CsvSource({
        "1,2,3",
        "2,3,5",
        "5,5,10"
})
void testAdd(
        int a,
        int b,
        int expected
) {

    assertEquals(
            expected,
            calculator.add(
                    a,
                    b
            )
    );
}

二十四、什么样的方法值得测试

例如:

金额计算

积分计算

权限判断

订单状态转换

字符串解析

参数校验

工具类

都很适合单元测试。


二十五、什么不是优秀单元测试

如果一个测试:

必须连接真实线上数据库

必须访问真实第三方接口

必须依赖真实短信服务

那么它通常已经不再是:

纯粹的单元测试

而更接近:

集成测试

二十六、单元测试的重要特点

好的单元测试通常希望:

快

稳定

独立

可重复

结果明确

二十七、测试之间不要互相依赖

不要设计:

test1
必须先执行

然后 test2
才能成功

理想情况:

每一个测试都可以独立运行

二十八、IDEA 2024.3 快速创建测试

在业务类中:

Ctrl + Shift + T

可以打开:

Create New Test

选择:

JUnit5

然后选择要测试的方法。


二十九、IDEA 快速运行测试

可以点击测试方法左侧:

绿色三角

运行单个测试。

也可以运行整个:

测试类

三十、测试通过和失败

通常 IDEA 会显示:

绿色
测试通过

红色
测试失败

注意:

测试失败
不等于测试代码一定错

它可能意味着:

业务代码出现 bug

三十一、常见问题:org.junit.jupiter.api 不存在

如果出现:

程序包 org.junit.jupiter.api 不存在

检查:

pom.xml 是否有 junit-jupiter

Maven 是否重新加载

依赖是否成功下载

测试类是不是放在 src/test/java

IDEA 是否识别 Maven 项目

三十二、Maven 重新加载

修改 pom.xml 后:

Maven 工具窗口
→ Reload All Maven Projects

或者点击:

重新加载图标

三十三、测试源目录问题

标准目录:

src/test/java

通常 Maven 导入后 IDEA 会自动识别为:

Test Sources Root

如果没有识别:

先确认项目是不是标准 Maven 结构

不要一开始就到处手工修改目录类型。


三十四、测试代码不要放 main

不推荐:

src/main/java
    CalculatorTest.java

应该:

src/test/java
    CalculatorTest.java

三十五、单元测试阶段总结

必须掌握:

@Test

assertEquals

assertTrue

assertFalse

assertNull

assertNotNull

assertThrows

@BeforeEach

@AfterEach

并理解:

测试业务逻辑
不是只看控制台输出

第二部分:配置文件

三十六、为什么需要配置文件

假设数据库配置写在 Java:

String url =
        "jdbc:mysql://localhost:3306/test";

String username =
        "root";

String password =
        "123456";

如果以后:

换数据库

换服务器

换端口

修改账号

就必须修改 Java 源码。

更合理:

把可变化的信息放在配置文件

三十七、什么信息适合配置

例如:

数据库地址

数据库账号

服务器端口

文件保存路径

第三方接口地址

功能开关

系统名称

超时时间

三十八、常见配置文件格式

Java 项目常见:

.properties

.xml

.yml

.yaml

.json

Java 基础阶段重点:

.properties

后面 SpringBoot 重点:

application.properties

application.yml

三十九、properties 基本格式

例如:

app.name=Java Blog
app.version=1.0
server.port=8080

结构:

key=value

四十、数据库配置例子

jdbc.url=jdbc:mysql://localhost:3306/student_db
jdbc.username=root
jdbc.password=123456

四十一、配置文件放在哪里

Maven 项目通常:

src/main/resources

例如:

src/main/resources
└─ app.properties

编译后会进入:

classpath

四十二、什么是 classpath

可以简单理解:

Java 程序运行时
用来查找类和资源的路径

Maven 中:

src/main/resources

的内容通常会复制到:

target/classes

四十三、读取 classpath 配置文件

推荐:

InputStream input =
        ConfigDemo.class
                .getClassLoader()
                .getResourceAsStream(
                        "app.properties"
                );

四十四、Properties 类

Java 提供:

java.util.Properties

专门处理:

key=value

类型配置。


四十五、读取 properties

Properties properties =
        new Properties();

try (
        InputStream input =
                ConfigDemo.class
                        .getClassLoader()
                        .getResourceAsStream(
                                "app.properties"
                        )
) {

    if (input == null) {

        throw new IllegalStateException(
                "配置文件不存在"
        );
    }

    properties.load(input);
}

四十六、获取配置

String appName =
        properties.getProperty(
                "app.name"
        );

例如:

String portText =
        properties.getProperty(
                "server.port"
        );

四十七、配置值默认都是字符串

properties:

server.port=8080

读取:

String portText =
        properties
                .getProperty(
                        "server.port"
                );

如果需要 int:

int port =
        Integer.parseInt(
                portText
        );

四十八、getProperty 默认值

String value =
        properties.getProperty(
                "app.name",
                "默认系统"
        );

如果不存在:

app.name

返回:

默认系统

四十九、配置文件注释

# 系统名称
app.name=Java Blog

也可以:

! comment

五十、配置工具类

可以封装:

public final class ConfigUtil {

    private static final Properties
            PROPERTIES =
            new Properties();

    static {

        try (
                InputStream input =
                        ConfigUtil.class
                                .getClassLoader()
                                .getResourceAsStream(
                                        "app.properties"
                                )
        ) {

            if (input == null) {

                throw new IllegalStateException(
                        "app.properties 不存在"
                );
            }

            PROPERTIES.load(
                    input
            );

        } catch (
                IOException e
        ) {

            throw new ExceptionInInitializerError(
                    e
            );
        }
    }

    private ConfigUtil() {

    }

    public static String get(
            String key
    ) {

        return PROPERTIES
                .getProperty(
                        key
                );
    }
}

使用:

String name =
        ConfigUtil.get(
                "app.name"
        );

五十一、为什么配置类常用 static

因为配置通常:

整个应用共享

没有必要:

每次 new 一个配置对象

所以经常:

类加载时读取一次

五十二、配置文件不是数据库

配置文件适合:

少量配置
相对稳定的数据

不适合:

海量用户数据
订单数据
业务流水

这些应该:

数据库

五十三、不要把敏感配置提交公共仓库

例如:

db.password=真实生产密码
api.secret=真实密钥

不要直接提交到公开 Git 仓库。

真实项目常通过:

环境变量

独立私有配置

配置中心

Secret 管理

处理。


五十四、环境变量简单了解

Java 可以读取:

String password =
        System.getenv(
                "DB_PASSWORD"
        );

这样:

密码不需要写在源码

五十五、系统属性

还可以:

System.getProperty(
        "app.env"
);

启动 JVM 时传入:

-Dapp.env=dev

后面 SpringBoot 会有更完整的:

外部化配置

体系。


五十六、配置优先级思维

真实项目可能同时存在:

默认配置

配置文件

环境变量

启动参数

配置中心

最终:

不同来源有优先级

SpringBoot 后面会专门处理。

当前先建立:

配置不要全部写死

这个意识。


五十七、XML 配置简单了解

例如:

<config>

    <database>

        <url>
            jdbc:mysql://localhost:3306/test
        </url>

        <username>
            root
        </username>

    </database>

</config>

XML 特点:

结构清晰

层级丰富

内容较冗长

五十八、为什么 MyBatis 常看到 XML

后面 MyBatis 会使用:

mybatis-config.xml

Mapper.xml

原因是 XML 适合描述:

复杂层级配置

SQL 映射

五十九、YAML 简单了解

例如:

server:
  port: 8080

spring:
  application:
    name: demo

后面 SpringBoot 常见:

application.yml

六十、配置文件常见错误

路径错误

例如:

Could not find resource

检查:

是否放在 src/main/resources

资源名称是否正确

是否写了多余路径

key 写错

配置:

server.port=8080

代码:

getProperty(
        "server.prot"
);

得到:

null

编码问题

现代项目尽量统一:

UTF-8

尤其 IDEA:

Project Encoding
Properties Encoding

要注意一致性。


六十一、配置文件阶段总结

需要掌握:

为什么使用配置文件

.properties 格式

src/main/resources

classpath

Properties

getResourceAsStream

getProperty

配置工具类

第三部分:JavaBean

六十二、JavaBean 是什么

JavaBean 可以理解为:

按照一定规范编写的普通 Java 类。

很多框架都喜欢操作这种标准化对象。

例如:

MyBatis

Servlet

JSP

Spring

SpringBoot

都大量和 JavaBean 打交道。


六十三、一个标准 JavaBean 示例

public class Student {

    private String name;

    private Integer age;

    public Student() {

    }

    public String getName() {

        return name;
    }

    public void setName(
            String name
    ) {

        this.name = name;
    }

    public Integer getAge() {

        return age;
    }

    public void setAge(
            Integer age
    ) {

        this.age = age;
    }
}

六十四、JavaBean 常见规范

通常包括:

1. 类是 public

2. 属性使用 private

3. 提供 public Getter / Setter

4. 提供无参构造

5. 根据需要实现 Serializable

六十五、为什么属性要 private

例如:

private String name;

这是:

封装

外部不直接修改:

字段

而通过:

getName()

setName()

访问。


六十六、Getter

public String getName() {

    return name;
}

用于:

读取属性

六十七、Setter

public void setName(
        String name
) {

    this.name = name;
}

用于:

修改属性

六十八、布尔属性 Getter

例如:

private boolean enabled;

Getter 通常:

public boolean isEnabled() {

    return enabled;
}

也可能看到:

getEnabled()

但传统 JavaBean 对 primitive boolean 常见:

isXxx

六十九、为什么需要无参构造

很多框架创建对象时会:

先调用无参构造
↓
再通过 Setter / 反射赋值

例如概念上:

Student student =
        new Student();

student.setName(
        "张三"
);

student.setAge(
        20
);

七十、如果自己写了有参构造

例如:

public Student(
        String name,
        Integer age
) {

}

Java 不会再自动提供:

默认无参构造

如果框架需要:

new Student()

就可能失败。

所以经常同时提供:

public Student() {

}

七十一、JavaBean 和普通类有什么区别

普通 Java 类:

怎么设计都可以

JavaBean:

遵循一套通用约定

好处:

框架容易识别

工具容易操作

属性读取规则统一

七十二、JavaBean 属性不是简单等于字段

这是很重要的概念。

JavaBean 认为:

属性

主要通过:

Getter / Setter

识别。

例如:

public String getUsername()

可能形成 Bean 属性:

username

七十三、属性名如何推导

方法:

getName()

对应:

name

方法:

setAge(...)

对应:

age

方法:

isEnabled()

对应:

enabled

七十四、为什么框架喜欢 JavaBean

假设 JSON:

{
    "name": "张三",
    "age": 20
}

框架可能根据属性名:

name
age

找到:

setName()

setAge()

然后自动填充。


七十五、数据库结果映射也类似

数据库:

name
age

映射到:

Student

框架会利用:

属性名
Setter
反射

完成对象赋值。

这就是后面 MyBatis 的基础。


七十六、JavaBean 完整示例

import java.io.Serializable;

public class User
        implements Serializable {

    private static final long
            serialVersionUID =
            1L;

    private Long id;

    private String username;

    private Integer age;

    private boolean enabled;

    public User() {

    }

    public User(
            Long id,
            String username,
            Integer age,
            boolean enabled
    ) {

        this.id = id;

        this.username =
                username;

        this.age = age;

        this.enabled =
                enabled;
    }

    public Long getId() {

        return id;
    }

    public void setId(
            Long id
    ) {

        this.id = id;
    }

    public String getUsername() {

        return username;
    }

    public void setUsername(
            String username
    ) {

        this.username =
                username;
    }

    public Integer getAge() {

        return age;
    }

    public void setAge(
            Integer age
    ) {

        this.age = age;
    }

    public boolean isEnabled() {

        return enabled;
    }

    public void setEnabled(
            boolean enabled
    ) {

        this.enabled =
                enabled;
    }

    @Override
    public String toString() {

        return "User{"
                + "id="
                + id
                + ", username='"
                + username
                + '\''
                + ", age="
                + age
                + ", enabled="
                + enabled
                + '}';
    }
}

七十七、IDEA 快速生成 Getter / Setter

Windows 默认快捷键:

Alt + Insert

然后选择:

Getter and Setter

选择字段:

生成

七十八、快速生成构造方法

同样:

Alt + Insert

选择:

Constructor

可以生成:

无参构造

有参构造

七十九、快速生成 toString()

Alt + Insert
→ toString()

八十、为什么不要手写大量模板代码

学习阶段:

建议理解代码含义

但实际项目中:

Getter
Setter
Constructor
toString

可以使用 IDEA 自动生成,

减少:

拼写错误
重复劳动

八十一、JavaBean 参数校验放哪

简单对象可以在 Setter 中:

public void setAge(
        Integer age
) {

    if (
        age != null
        && age < 0
    ) {

        throw new IllegalArgumentException(
                "年龄不能小于 0"
        );
    }

    this.age = age;
}

但大型 Web 项目通常会使用:

Service 校验

Bean Validation

DTO 校验

不要把所有复杂业务逻辑塞进 Bean。


八十二、Entity、DTO、VO 和 JavaBean

后面会看到:

Entity
DTO
VO
POJO

它们很多本质上都可以:

遵循 JavaBean 风格

只是:

业务角色不同

八十三、POJO 是什么

POJO:

Plain Old Java Object

可以理解:

普通 Java 对象

通常:

不强制继承框架类
不依赖复杂框架接口

JavaBean 可以看作:

更加遵循特定规范的 POJO

八十四、JavaBean 和实体类

例如:

public class Student {

    private Long id;

    private String name;
}

这个对象既可能叫:

实体类

同时也可以符合:

JavaBean 规范

这两个词关注点不同。


八十五、综合案例:配置 + JavaBean

配置文件:

app.name=学生管理系统
app.version=1.0
app.maxUsers=100

Bean:

public class AppConfig {

    private String name;

    private String version;

    private Integer maxUsers;

    public AppConfig() {

    }

    // Getter / Setter
}

八十六、手动读取配置到 Bean

Properties properties =
        new Properties();

try (
        InputStream input =
                Demo.class
                        .getClassLoader()
                        .getResourceAsStream(
                                "app.properties"
                        )
) {

    properties.load(
            input
    );
}

AppConfig config =
        new AppConfig();

config.setName(
        properties
                .getProperty(
                        "app.name"
                )
);

config.setVersion(
        properties
                .getProperty(
                        "app.version"
                )
);

config.setMaxUsers(
        Integer.parseInt(
                properties
                        .getProperty(
                                "app.maxUsers"
                        )
        )
);

八十七、这就是框架自动配置的雏形

你现在是:

手动读取 properties
↓
手动 new Bean
↓
手动 set 属性

后面 SpringBoot 会变成:

自动读取配置
↓
自动创建 Bean
↓
自动绑定属性

所以现在这些基础非常重要。


八十八、综合案例:JavaBean + 单元测试

例如 User:

public class User {

    private String username;

    public String getUsername() {

        return username;
    }

    public void setUsername(
            String username
    ) {

        this.username =
                username;
    }
}

测试:

@Test
void shouldSetUsername() {

    User user =
            new User();

    user.setUsername(
            "admin"
    );

    assertEquals(
            "admin",
            user.getUsername()
    );
}

八十九、配置工具类测试

例如:

@Test
void shouldReadAppName() {

    String appName =
            ConfigUtil.get(
                    "app.name"
            );

    assertNotNull(
            appName
    );
}

这样:

配置是否正确

也可以自动检查。


九十、三个知识点的关系

可以用一张图理解:

配置文件
负责保存可变化的数据
        │
        ▼
JavaBean
负责承载结构化数据
        │
        ▼
业务代码
负责处理逻辑
        │
        ▼
JUnit
负责验证逻辑是否正确

九十一、进入框架前必须建立的习惯

第一阶段经常写:

public static void main(...)

第二阶段开始应该逐渐建立:

业务类单独写

配置单独放

测试单独写

对象遵循规范

这就是:

工程化

的开始。


九十二、常见错误:业务配置写死

不推荐:

String uploadPath =
        "D:\\project\\upload";

更好:

配置文件

九十三、常见错误:测试只打印

不推荐:

System.out.println(
        result
);

推荐:

assertEquals(
        expected,
        actual
);

九十四、常见错误:测试依赖执行顺序

不推荐:

test1 创建数据

test2 必须使用 test1 数据

测试应该尽量:

彼此独立

九十五、常见错误:测试真实生产数据

单元测试不要直接:

删除生产数据库数据

调用真实支付接口

发送真实短信

测试环境必须:

和生产隔离

九十六、常见错误:配置文件放错位置

Maven 中:

src/main/resources

是非常重要的资源目录。

例如:

mybatis-config.xml
application.properties
jdbc.properties

以后都会放这里。


九十七、常见错误:new File(“src/main/resources/…”)

开发阶段可能能运行:

new File(
        "src/main/resources/app.properties"
);

但打包成 jar 后:

src/main/resources

已经不存在。

classpath 资源应该优先通过:

ClassLoader

读取。


九十八、常见错误:JavaBean 没有无参构造

如果框架需要:

new User()

却只有:

public User(
        String name
)

可能创建失败。

所以传统 JavaBean 通常提供:

无参构造

九十九、常见错误:字段全部 public

不推荐:

public String name;

推荐:

private String name;

再通过:

Getter / Setter

访问。


一百、常见错误:Getter 命名不规范

不推荐:

public String readName() {

}

如果你希望它被标准 JavaBean 工具识别为属性:

name

更标准:

getName()

一百零一、练习题 1:Calculator 单元测试

创建:

Calculator

包含:

add
subtract
multiply
divide

为每一个方法编写:

JUnit 测试

一百零二、练习题 2:异常测试

要求:

divide(10, 0)

抛出:

IllegalArgumentException

使用:

assertThrows()

测试。


一百零三、练习题 3:UserService 测试

创建:

boolean isAdult(
        int age
)

测试:

18
17
20
0

一百零四、练习题 4:配置文件

创建:

system.properties

内容:

system.name
system.version
system.port

然后 Java 读取并输出。


一百零五、练习题 5:ConfigUtil

封装:

ConfigUtil.get(
        String key
)

并为它写单元测试。


一百零六、练习题 6:Student JavaBean

字段:

id
studentNo
name
age
major
score

要求:

private 字段

无参构造

有参构造

Getter / Setter

toString

一百零七、练习题 7:配置绑定

配置:

student.defaultAge=18
student.defaultMajor=软件工程

读取后:

创建 Student 对象

一百零八、本章必须掌握

单元测试

JUnit 是什么

@Test

断言

@BeforeEach

assertThrows

测试目录

配置文件

为什么配置外置

properties

resources

classpath

Properties

getResourceAsStream

JavaBean

private 属性

Getter / Setter

无参构造

标准命名

框架为什么喜欢 Bean

一百零九、IDEA 快捷操作总结

创建测试

Ctrl + Shift + T

生成 Getter / Setter

Alt + Insert

然后:

Getter and Setter

生成构造方法

Alt + Insert
→ Constructor

生成 toString

Alt + Insert
→ toString()

一百一十、本章总结

这三个知识点表面上看并不完全一样,

但它们都在帮我们从:

“写几个 Java 方法”

进入:

“写一个更正规的 Java 项目”

具体来说:

JUnit
解决代码怎么自动验证

配置文件
解决变化的数据怎么从代码中分离

JavaBean
解决对象怎样标准化

它们会直接影响后面的:

MyBatis

Servlet

JSP

Spring

SpringBoot

尤其后面你会不断看到:

Bean

配置

测试

资源目录

属性绑定

所以这不是几个零散小知识,

而是正式进入 Java 框架开发前的基础准备。

下一篇继续整理:

单例模式

匿名内部类

枚举

把第一项课程中剩下的面向对象补充内容完整收尾。