9.5 KiB
Raw Permalink Blame History

本次实验的主要任务是完成期末案例的实体类开发和单元测试并且熟悉IDEA工具的代码自动生成功能。

环境准备

{{< admonition warning >}} 每天的代码要保留一份单独的压缩包,命名示例:day1.rar {{< /admonition >}}

  1. 导入JUnit依赖下方两个包放到lib目录
  2. 配置好MySQL数据库参考Day 1

junit-4.13.2.jar 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

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自动生成所有属性的gettersetter方法

1.2 审批状态枚举ApprovalStatus.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

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

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

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. 定期运行所有测试,确保修改不会影响其他功能