308 lines
9.5 KiB
Markdown
308 lines
9.5 KiB
Markdown
本次实验的主要任务是完成期末案例的实体类开发和单元测试,并且熟悉IDEA工具的代码自动生成功能。
|
||
|
||
## 环境准备
|
||
|
||
|
||
{{< admonition warning >}}
|
||
每天的代码要保留一份单独的压缩包,命名示例:`day1.rar`
|
||
{{< /admonition >}}
|
||
|
||
1. 导入JUnit依赖(下方两个包放到lib目录)
|
||
2. 配置好MySQL数据库(参考Day 1)
|
||
|
||
[junit-4.13.2.jar](https://static.seahi.me/2024/12/junit-4.13.2.jar)
|
||
[hamcrest-core-1.3.jar](https://static.seahi.me/2024/12/hamcrest-core-1.3.jar)
|
||
|
||
{{< admonition quote 包说明>}}
|
||
1. junit-4.13.2.jar 是一个用来测试Java程序的工具
|
||
2. hamcrest-core-1.3.jar 是JUnit工具的依赖包
|
||
{{< /admonition >}}
|
||
|
||
## 任务内容
|
||
|
||
### 1. 实体类开发
|
||
|
||
#### 1.1 请假申请实体类(LeaveRequest.java)
|
||
|
||
```java
|
||
package model;
|
||
|
||
import java.util.Date;
|
||
|
||
/**
|
||
* 请假条实体类
|
||
*/
|
||
public class LeaveRequest {
|
||
private int id; // 数据库主键ID
|
||
private Student student; // 学生信息
|
||
private Date startTime; // 开始时间
|
||
private Date endTime; // 结束时间
|
||
private double duration; // 时长
|
||
private String location; // 外出地址
|
||
private String reasonType; // 外出事由类型
|
||
private String reasonDetail; // 详细事由
|
||
private boolean isLeavingCity; // 是否离津
|
||
private ApprovalStatus status; // 审批状态
|
||
private Teacher approver; // 审批人
|
||
private String approvalComment; // 审批意见
|
||
private Date requestTime; // 申请时间
|
||
private Date approvalTime; // 审批时间
|
||
|
||
// 构造方法
|
||
// getter和setter方法
|
||
}
|
||
```
|
||
|
||
**操作步骤:**
|
||
1. 在`src/model`目录下创建`LeaveRequest.java`文件
|
||
2. 复制上述代码框架
|
||
3. 实现默认构造方法,设置初始状态为`PENDING`
|
||
4. 使用IDE**自动生成**所有属性的`getter`和`setter`方法
|
||
|
||
#### 1.2 审批状态枚举(ApprovalStatus.java)
|
||
|
||
> 该文件的代码是完整的,无需修改
|
||
|
||
```java
|
||
package model;
|
||
|
||
/**
|
||
* 请假审批状态枚举类
|
||
*/
|
||
public enum ApprovalStatus {
|
||
PENDING("待审批"), // 等待审批
|
||
APPROVED("已批准"), // 已经批准
|
||
REJECTED("已驳回"); // 已经驳回
|
||
|
||
private final String description; // 状态描述
|
||
|
||
ApprovalStatus(String description) {
|
||
this.description = description;
|
||
}
|
||
|
||
public String getDescription() {
|
||
return description;
|
||
}
|
||
}
|
||
```
|
||
|
||
> enum是枚举类型,用于表示一组固定的常量。
|
||
|
||
|
||
|
||
{{< admonition >}}
|
||
类似地步骤,完成`Teacher`实体类和`Student`实体类
|
||
{{< /admonition >}}
|
||
|
||
#### 1.3 教师实体类(Teacher.java)
|
||
|
||
```java
|
||
package model;
|
||
|
||
/**
|
||
* 教师实体类
|
||
*/
|
||
public class Teacher {
|
||
private int id; // 数据库主键ID
|
||
private String teacherId; // 教师工号
|
||
private String name; // 教师姓名
|
||
private String department; // 所属部门
|
||
private String contact; // 联系方式
|
||
private String password; // 登录密码
|
||
|
||
// 使用 IDE 自动生成以下内容:
|
||
// 构造方法
|
||
// getter 和 setter 方法
|
||
}
|
||
```
|
||
### 2. 单元测试开发
|
||
|
||
**什么是单元测试?**
|
||
|
||
单元测试是检查程序中最小单位(一个方法、一个功能)是否正确运行的测试。
|
||
|
||
**为什么要做单元测试?**
|
||
- 及早发现程序中的错误
|
||
- 确保修改代码后,原有功能仍然正常
|
||
- 节省手工测试的时间
|
||
|
||
**单元测试的优点**
|
||
- 自动化:写好测试代码后可以反复运行
|
||
- 快速:一次能测试多个功能点
|
||
- 可靠:比人工测试更准确
|
||
|
||
在实际开发中,单元测试是保证代码质量的重要手段。以后你们进入公司工作,很可能会遇到需要写单元测试的要求。对Java代码进行单元测试,常用的工具(包)是Junit
|
||
|
||
{{< admonition success 注意>}}
|
||
本次任务需要了解单元测试的意义、方法,后期的单元测试代码会给同学们提供完整代码。
|
||
{{< /admonition >}}
|
||
|
||
#### 2.1 创建测试目录
|
||
|
||
1. 在`src`目录下创建`test`目录
|
||
2. 在`test`目录下创建`model`子目录
|
||
3. 在`test/model`目录下创建各个测试类
|
||
|
||
#### 2.2 编写Teacher测试类(TeacherTest.java)
|
||
|
||
```java
|
||
package test.model;
|
||
|
||
import model.Teacher;
|
||
import org.junit.Test;
|
||
import static org.junit.Assert.*;
|
||
|
||
public class TeacherTest {
|
||
|
||
@Test
|
||
public void testConstructorAndGetters() {
|
||
String teacherId = "T001";
|
||
String name = "张老师";
|
||
String department = "计算机系";
|
||
String contact = "13800138000";
|
||
String password = "password123";
|
||
|
||
Teacher teacher = new Teacher(teacherId, name, department, contact, password);
|
||
|
||
assertEquals("教师工号应匹配", teacherId, teacher.getTeacherId());
|
||
assertEquals("教师姓名应匹配", name, teacher.getName());
|
||
assertEquals("所属部门应匹配", department, teacher.getDepartment());
|
||
assertEquals("联系方式应匹配", contact, teacher.getContact());
|
||
assertEquals("密码应匹配", password, teacher.getPassword());
|
||
}
|
||
|
||
@Test
|
||
public void testSetters() {
|
||
Teacher teacher = new Teacher();
|
||
|
||
int id = 1;
|
||
String teacherId = "T002";
|
||
String name = "李老师";
|
||
String department = "数学系";
|
||
String contact = "13900139000";
|
||
String password = "newpass123";
|
||
|
||
teacher.setId(id);
|
||
teacher.setTeacherId(teacherId);
|
||
teacher.setName(name);
|
||
teacher.setDepartment(department);
|
||
teacher.setContact(contact);
|
||
teacher.setPassword(password);
|
||
|
||
assertEquals("ID应匹配", id, teacher.getId());
|
||
assertEquals("教师工号应匹配", teacherId, teacher.getTeacherId());
|
||
assertEquals("教师姓名应匹配", name, teacher.getName());
|
||
assertEquals("所属部门应匹配", department, teacher.getDepartment());
|
||
assertEquals("联系方式应匹配", contact, teacher.getContact());
|
||
assertEquals("密码应匹配", password, teacher.getPassword());
|
||
}
|
||
}
|
||
```
|
||
|
||
**操作步骤:**
|
||
1. 创建TeacherTest.java文件
|
||
2. 编写构造方法测试用例
|
||
3. 编写getter/setter方法测试用例
|
||
|
||
#### 2.4 编写DatabaseUtil测试类(DatabaseUtilTest.java)
|
||
|
||
```java
|
||
package test.util;
|
||
|
||
import org.junit.Test;
|
||
import util.DatabaseUtil;
|
||
|
||
import java.sql.Connection;
|
||
import java.sql.SQLException;
|
||
|
||
import static org.junit.Assert.*;
|
||
|
||
public class DatabaseUtilTest {
|
||
|
||
@Test
|
||
public void testGetConnection() {
|
||
try (Connection conn = DatabaseUtil.getConnection()) {
|
||
// 验证连接不为空
|
||
assertNotNull("数据库连接不应该为空", conn);
|
||
// 验证连接是否有效
|
||
assertTrue("数据库连接应该是有效的", !conn.isClosed());
|
||
} catch (SQLException e) {
|
||
fail("获取数据库连接时发生异常: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
@Test
|
||
public void testConnectionAutoClose() {
|
||
Connection conn = null;
|
||
try {
|
||
// 在try-with-resources块中获取连接
|
||
try (Connection autoCloseConn = DatabaseUtil.getConnection()) {
|
||
assertNotNull("数据库连接不应该为空", autoCloseConn);
|
||
assertTrue("连接应该是开启状态", !autoCloseConn.isClosed());
|
||
}
|
||
// try-with-resources块结束后,获取一个新连接来测试
|
||
conn = DatabaseUtil.getConnection();
|
||
assertNotNull("新的数据库连接不应该为空", conn);
|
||
assertTrue("新的连接应该是开启状态", !conn.isClosed());
|
||
} catch (SQLException e) {
|
||
fail("测试连接自动关闭时发生异常: " + e.getMessage());
|
||
} finally {
|
||
if (conn != null) {
|
||
try {
|
||
conn.close();
|
||
} catch (SQLException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**操作步骤:**
|
||
1. 在test.util包下创建DatabaseUtilTest.java文件
|
||
2. 编写测试数据库连接的方法testGetConnection()
|
||
3. 编写测试连接自动关闭的方法testConnectionAutoClose()
|
||
4. 确保使用try-with-resources语句来自动管理数据库连接资源
|
||
|
||
## 完成标准
|
||
|
||
- [ ] 所有实体类完整实现
|
||
- [ ] Teacher类(属性、构造方法、getter/setter)
|
||
- [ ] Student类(属性、构造方法、getter/setter)
|
||
- [ ] LeaveRequest类(属性、构造方法、getter/setter)
|
||
- [ ] ApprovalStatus枚举(所有状态值和描述)
|
||
- [ ] 所有单元测试通过
|
||
- [ ] TeacherTest全部测试用例通过
|
||
- [ ] DatabaseUtilTest全部测试用例通过
|
||
- [ ] 代码规范
|
||
- [ ] 适当的注释说明
|
||
- [ ] 规范的命名
|
||
- [ ] 合理的代码组织
|
||
|
||
## 编码规范
|
||
|
||
1. 类名使用大驼峰命名法(如:`TeacherTest`)
|
||
2. 方法名使用小驼峰命名法(如:`testConstructor`)
|
||
3. 变量名使用小驼峰命名法(如:`teacherId`)
|
||
4. 常量使用全大写(如:`PENDING`)
|
||
5. 每个类都要有类注释
|
||
6. 重要方法要有方法注释
|
||
|
||
## 测试运行方法
|
||
|
||
1. 在IDE中右键点击test包
|
||
2. 选择"Run 'Tests in test'" 运行所有测试类
|
||
3. 或右键点击test内的某个包,选择"Run 'Tests in 包名'"运行包内所有测试
|
||
4. 或右键点击单个测试类,选择"Run 'Tests in 类名'"运行单个测试类
|
||
5. 查看测试结果:绿色√表示通过,红色×表示失败
|
||
|
||
|
||
## 提示与建议
|
||
|
||
1. 使用IDE的代码生成功能可以快速生成getter/setter方法
|
||
2. 测试用例要考虑各种可能的情况
|
||
3. 测试失败时要仔细阅读错误信息
|
||
4. 定期运行所有测试,确保修改不会影响其他功能
|
||
|