第一次个人编程作业

作业信息

项目 内容
这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class56-Grade2024-CS
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class56-Grade2024-CS/homework/15693
这个作业的目标 完成一个论文查重程序,实践需求分析、设计、编码、测试、性能分析与代码质量检查等软件开发流程

第一次个人编程作业:论文查重

一、GitHub链接

二、PSP表格

在开始实现程序之前,我估计将在程序的各个模块的开发上耗费的时间如下:

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 25
· Estimate · 估计这个任务需要多少时间 20 25
Development 开发 180 200
· Analysis · 需求分析 (包括学习新技术) 30 40
· Design Spec · 生成设计文档 20 15
· Design Review · 设计复审 10 10
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 10
· Design · 具体设计 20 20
· Coding · 具体编码 60 80
· Code Review · 代码复审 10 15
· Test · 测试(自我测试,修改代码,提交修改) 30 30
Reporting 报告 30 30
· Test Report · 测试报告 10 10
· Size Measurement · 计算工作量 10 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 10 10
合计 230 255

三、计算模块接口的设计与实现过程

3.1 代码组织

本项目采用 Python 实现,主要包含以下文件和类:

  • main.py: 主入口,负责解析命令行参数,调用核心算法,输出结果。
  • test_main.py: 单元测试文件。

3.2 算法关键

本程序使用 difflib 库中的 SequenceMatcher 算法来计算两段文本的相似度。

  • 核心思路:SequenceMatcher 通过计算两个序列的最长连续匹配子序列,进而得出相似度比值(ratio)。
  • 独到之处:相对于传统的编辑距离算法,SequenceMatcher 对长文本的处理效率更高,且能自动忽略一些不必要的标点干扰。

四、计算模块接口部分的性能改进

4.1 性能分析

使用 cProfile 对程序进行性能分析,发现主要耗时在 SequenceMatcher 的匹配计算上。

4.2 改进思路与结果

  • 改进思路:在处理大文本时,可以先进行文本预处理(去除换行符和多余空格),减少输入序列的长度。
  • 改进结果:经过预处理后,长文本的对比时间显著缩短,内存占用也有所降低。

性能分析图:

e8db2862c966b7d05858793ed0ba795a

五、计算模块部分单元测试展示

5.1 测试代码

import unittest
from main import calculate_similarity

class TestSimilarity(unittest.TestCase):
    # 测试用例1:两段文本完全相同
    def test_identical(self):
        self.assertEqual(calculate_similarity("今天天气晴", "今天天气晴"), 1.00)

    # 测试用例2:两段文本完全不同
    def test_different(self):
        self.assertEqual(calculate_similarity("ABC", "XYZ"), 0.00)

    # 测试用例3:部分相似
    def test_partial(self):
        self.assertTrue(0 < calculate_similarity("今天是星期天", "今天是周天") < 1)

    # 测试用例4:空字符串 vs 空字符串
    def test_empty_both(self):
        self.assertEqual(calculate_similarity("", ""), 1.00)

    # 测试用例5:一段空,一段非空
    def test_one_empty(self):
        self.assertEqual(calculate_similarity("ABC", ""), 0.00)

    # 测试用例6:标点符号差异
    def test_punctuation(self):
        self.assertTrue(0 < calculate_similarity("你好,世界!", "你好世界") < 1)

    # 测试用例7:包含换行符
    def test_newline(self):
        self.assertEqual(calculate_similarity("Hello\nWorld", "Hello\nWorld"), 1.00)

    # 测试用例8:长文本
    def test_long_text(self):
        text1 = "这是一个非常长的测试文本,用于检验算法在长文本下的表现。" * 10
        text2 = "这是一个非常长的测试文本,用于检验算法在长文本下的表现。" * 10
        self.assertEqual(calculate_similarity(text1, text2), 1.00)

    # 测试用例9:单字符相同
    def test_single_char(self):
        self.assertEqual(calculate_similarity("A", "A"), 1.00)

    # 测试用例10:单字符不同
    def test_single_char_diff(self):
        self.assertEqual(calculate_similarity("A", "B"), 0.00)

if __name__ == '__main__':
    unittest.main()

5.2 测试覆盖率

使用 coverage 工具运行测试,结果如下:

测试覆盖率截图

5.3 构造测试数据的思路

  1. 边界测试:空字符串、单字符、超长文本。
  2. 功能测试:完全相同、完全不同、部分相同(增删改)。
  3. 异常测试:文件不存在、文件编码错误。

六、计算模块部分异常处理说明

本程序在设计中充分考虑了各种异常情况,以保证程序的健壮性。以下列举两种典型的异常处理及其对应的单元测试场景:

6.1 文件不存在异常(FileNotFoundError)

  • 设计目标:当用户输入的文件路径不存在时,程序不应直接崩溃,而应给出友好的提示,并优雅退出。
  • 错误场景:用户在命令行传入了一个不存在的文件路径,如 python main.py no_exist.txt plag.txt ans.txt
  • 单元测试样例
def test_file_not_found(self):
    # 模拟调用读取不存在文件的情况
    with self.assertRaises(SystemExit):
        read_file("no_exist.txt")

6.2 文件编码错误异常(UnicodeDecodeError)

  • 设计目标:当读取的文件不是 UTF-8 编码(例如 GBK 编码)时,程序应捕获异常并提示用户转换编码。
  • 错误场景:用户提供了一个使用 GBK 编码保存的文本文件,程序默认以 UTF-8 读取,触发解码错误。
  • 单元测试样例
def test_encoding_error(self):
    # 模拟读取非 UTF-8 编码文件的场景
    with self.assertRaises(UnicodeDecodeError):
        read_file("gbk_encoded.txt")

七、总结与改进

通过本次个人编程作业,我完整地实践了从环境搭建、代码编写到单元测试、版本控制的软件工程流程,收获颇丰。

主要收获:

  1. 掌握了 Git 版本控制:学会了 git addgit commitgit push 等基础操作,理解了代码"存档"与回溯的意义。
  2. 熟悉了单元测试:通过 unittestcoverage 工具,学会了编写边界测试用例并查看代码覆盖率,明白了程序健壮性的重要性。
  3. 理解了性能分析:使用 cProfile 工具定位了性能瓶颈,认识到算法选择对程序效率的影响。

不足与改进:

  1. PSP 时间预估不够准确,实际耗时比预估要多,今后需要更理性地评估任务时间。
  2. 目前的查重算法对超长文本的处理效率有限,未来可以尝试使用 SimHash 等更高效的算法进行优化。
  3. 测试用例主要覆盖了常规边界情况,对异常路径的测试还不够充分,今后应加强异常处理的测试。

总的来说,本次作业让我从"只会写代码"向"会做软件工程"迈出了重要的一步,今后会继续在实践中提升自己的工程能力。


八、附录:PSP 实际耗时记录表

在实现完程序之后,我在下述 PSP 表格中记录了各个模块实际花费的时间:

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 25
· Estimate · 估计这个任务需要多少时间 20 25
Development 开发 180 200
· Analysis · 需求分析(包括学习新技术) 30 40
· Design Spec · 生成设计文档 20 15
· Design Review · 设计复审 10 10
· Coding Standard · 代码规范(为目前的开发制定合适的规范) 10 10
· Design · 具体设计 20 20
· Coding · 具体编码 60 80
· Code Review · 代码复审 10 15
· Test · 测试(自我测试,修改代码,提交修改) 30 30
Reporting 报告 30 30
· Test Report · 测试报告 10 10
· Size Measurement · 计算工作量 10 10
· Postmortem & Process Improvement Plan · 事后总结,并提出过程改进计划 10 10
合计 230 255
posted @ 2026-09-15 22:06  Alan900447  阅读(5)  评论(0)    收藏  举报