软件工程第二次作业

这个作业属于哪个课程 我所在的班级
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class78-Grade2024-CS/homework/15702
这个作业的目标 尝试完成一份“软件工程作业”,包含测试等完成流程

作业 GitHub 链接:https://github.com/morganalter/paper-check-homework/tree/main/3124004485

一、PSP表格

PSP2.1 阶段 中文说明 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 20
· Estimate 估计任务总时间 20 20
Development 开发 240 280
· Analysis 需求分析 + 学习相关技术 30 40
· Design Spec 梳理设计思路 20 25
· Design Review 设计自查 10 25
· Coding Standard 制定代码规范 10 15
· Design 模块与函数设计 30 30
· Coding 编写代码 80 85
· Code Review 代码检查 20 25
· Test 自测 + 修改 bug 40 40
Reporting 报告与总结 90 80
· Test Repor 整理测试报告 30 30
· Size Measurement 统计工作量 10 10
· Postmortem & Process Improvement Plan 事后总结 + 改进计划 50 50
合计 350 425

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

2.1 模块组织与接口设计
程序采用模块化分层设计,共包含 5 个功能函数与 1 个主入口函数。

函数 输入 输出 核心职责
clean_text(text) 原始文本字符串 清洗后的纯文本字符串 去除标点、空格、换行符等无关字符,统一文本格式
seg_words(text) 清洗后的文本 分词结果列表 调用 jieba 精确模式完成中文分词,过滤空字符
calc_cosine_similarity(text1, text2) 两篇原始文本 相似度浮点数值 词频统计、向量构建、余弦相似度计算
read_file(file_path) 文件路径字符串 文件内容字符串 UTF-8 编码文件读取与异常捕获
write_result(file_path, score) 输出路径、相似度值 格式化输出结果到指定文件
main() 命令行参数 参数校验、流程调度、全局异常处理

调用关系为线性流程:main()read_file() 读取两篇文本 → calc_cosine_similarity() 内部依次调用 clean_text()seg_words() 完成预处理与分词 → 计算相似度 → write_result() 写入结果。

2.2 核心算法原理

程序基于词袋模型 + 余弦相似度算法实现文本查重,核心思路如下:

  1. 文本预处理:通过正则表达式去除非文本字符,消除格式差异对结果的干扰。
  2. 中文分词:将连续的中文文本拆分为独立词语,作为向量化的基本单元。
  3. 词频向量化:统计每篇文本中每个词语的出现次数,构建词频向量。
  4. 余弦相似度计算:计算两个词频向量夹角的余弦值,数值越接近 1 代表文本重合度越高。

2.3 设计独到之处
文本清洗、分词、相似度计算、文件读写完全独立,可单独测试、替换与优化,扩展性强。

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

3.1 改进思路
核心思路为:先通过性能分析工具定位瓶颈,再针对自研代码的可优化点进行定向改进。

优化前先通过 cProfile 采集全函数耗时数据,定位到两类可优化点:一是重复执行的编译类操作,二是 Python 层的显式循环。据此实施四项针对性优化:正则表达式预编译、分词词典预加载、Counter 内置词频统计、列表推导式替代 for 循环。

3.2 性能分析结果
使用 Python 标准性能分析工具 cProfile 采集数据,结合 snakeviz 生成可视化调用树图,如下所示:

image
image
上图为优化前版本性能分析图,程序总耗时 0.5748 秒,其中消耗最大的函数为 marshal.load,累计耗时 0.443 秒,占总耗时约 77%,属于第三方中文分词库的固有初始化开销,自研业务代码部分累计耗时最长为calc_cosine_similarity

e7db86f02adc7be3a09c3c91adbf9b3a
image
上图为优化后版本性能分析图
优化后程序总耗时 0.553 秒,自研业务代码自身耗时降低约 30%,核心瓶颈仍为 jieba 词典加载,属于第三方库固定开销,自研业务代码部分优化后累计耗时最长为main

3.3 优化效果对比

优化点 优化前实现 优化后实现 性能提升
正则编译 每次调用实时编译 模块顶层预编译 文本清洗模块耗时降低 49%
词典加载 首次分词时触发加载 程序启动主动预加载 业务执行阶段无突发卡顿
词频统计 手写字典 + for 循环 collections.Counter 内置实现 词频统计模块耗时降低 41%
分词过滤 for 循环 + append 列表推导式 分词过滤环节耗时降低 25%

整体来看,自研业务代码自身性能提升约 30%,优化措施均达到预期效果。优化后总耗时稳定在 0.55 秒左右,远低于作业要求的 5 秒上限。

四、计算模块接口部分的单元测试
4.1 测试设计思路
基于 Python 标准 unittest 框架编写单元测试用例,覆盖正常功能、边界条件、异常输入三类场景,对计算模块的每个核心函数进行逐项验证。

4.2 核心单元测试代码示例
(1)文本清洗模块测试

  • 测试函数clean_text(text)
  • 测试目标:验证函数可正确去除标点、空格、换行符等无关字符,仅保留中英文与数字。
  • 数据构造思路:构造三类测试文本:包含混合标点与换行的正常文本、空文本、纯标点文本,分别验证正常清洗、边界输入、极端输入的处理效果。

代码:
import unittest
from main import clean_text

class TestCleanText(unittest.TestCase):
def test_clean_text_normal(self):
"""正常场景:混合标点、空格、换行的文本清洗"""
input_text = "你好,世界!\nHello World. 123"
self.assertEqual(clean_text(input_text), "你好世界HelloWorld123")

def test_clean_text_empty(self):
"""边界场景:空文本输入"""
self.assertEqual(clean_text(""), "")

def test_clean_text_only_punctuation(self):
"""极端场景:纯标点符号输入"""
self.assertEqual(clean_text(",。!?、"), "")
(2)余弦相似度计算模块测试

  • 测试函数calc_cosine_similarity(text1, text2)
  • 测试目标:验证相似度计算逻辑的正确性,覆盖不同重合度的文本场景。
  • 数据构造思路:构造四组对照文本:完全相同文本、完全无关文本、部分重复文本、空文本与正常文本,分别验证相似度极值、中间值与边界表现。
    代码:
    import unittest
    from main import calc_cosine_similarity

class TestCosineSimilarity(unittest.TestCase):
def test_similarity_identical(self):
"""边界场景:完全相同文本,相似度应接近1"""
score = calc_cosine_similarity("今天天气很好适合出门", "今天天气很好适合出门")
self.assertAlmostEqual(score, 1.0, places=1)

def test_similarity_different(self):
"""边界场景:完全无关文本,相似度应接近0"""
score = calc_cosine_similarity("今天天气很好", "机器学习算法技术")
self.assertLess(score, 0.3)

def test_similarity_partial(self):
"""正常场景:部分重复文本,相似度应在0-1之间"""
score = calc_cosine_similarity("今天天气很好适合出去玩", "今天天气很好适合在家学习")
self.assertGreater(score, 0.5)
self.assertLess(score, 1.0)

def test_similarity_empty(self):
"""边界场景:空文本输入,相似度应为0"""
score = calc_cosine_similarity("", "测试文本内容")
self.assertEqual(score, 0.0)

(3)文件操作异常测试

  • 测试函数read_file(file_path)
  • 测试目标:验证文件不存在等异常场景下的错误处理逻辑。
  • 数据构造思路:传入不存在的文件路径,触发文件未找到异常,验证程序是否正常捕获并退出。
    代码:
    import unittest
    from main import read_file

class TestFileException(unittest.TestCase):
def test_read_file_not_exist(self):
"""异常场景:读取不存在的文件"""
with self.assertRaises(SystemExit):
read_file("nonexistent_file.txt")

4.3 测试覆盖率结果

使用 coverage 工具统计单元测试代码覆盖率,结果如下:
a6df14cd8cdb292dd9c5c49b25d9ca9c
如图所示,总代码覆盖率 89%,核心业务代码 main.py 覆盖率 77%。未覆盖部分为极端异常兜底分支,不影响核心功能的正确性与稳定性。

五.计算模块部分异常处理说明
5.1 命令行参数数量异常

  • 设计目标:当用户传入的命令行参数数量不符合要求时,输出清晰的使用格式说明,引导用户正确调用程序,避免程序直接抛出晦涩的索引越界错误。
  • 触发场景:运行程序时未传参数、仅传 1-2 个参数、传入 4 个及以上参数。
  • 处理逻辑:在main()函数入口处校验sys.argv的长度,若不等于 4 则打印标准使用格式python main.py 原文文件 比对文件 结果文件,随后以正常状态码退出程序。
    对应单元测试样例代码:
    import sys
    import unittest
    from unittest.mock import patch
    from main import main

class TestExceptionHandle(unittest.TestCase):
def test_arg_count_error(self):
"""验证参数数量不足时,程序输出使用说明并正常退出"""
# 模拟命令行仅传入程序名,无业务参数
with patch.object(sys, 'argv', ['main.py']):
with self.assertRaises(SystemExit) as cm:
main()
# 验证退出状态码为正常退出
self.assertEqual(cm.exception.code, 1)

5.2 文件不存在异常

  • 设计目标:当输入的原文文件或比对文件路径不存在时,明确提示缺失的文件路径,帮助用户快速定位输入错误,而非抛出通用文件错误。
  • 触发场景:文件名拼写错误、文件路径错误、目标文件已被删除。
  • 处理逻辑:在read_file()函数中捕获FileNotFoundError异常,格式化输出错误:文件 {file_path} 不存在的提示信息,随后退出程序。

对应单元测试样例代码:
import unittest
from main import read_file

class TestExceptionHandle(unittest.TestCase):
def test_file_not_exist(self):
"""验证读取不存在的文件时,程序捕获异常并退出"""
with self.assertRaises(SystemExit) as cm:
read_file('nonexistent_original.txt')
self.assertEqual(cm.exception.code, 1)

5.3 文件读写通用异常

  • 设计目标:兜底处理所有文件操作相关的其他异常,包括编码错误、无读写权限、文件损坏等场景,输出具体错误原因,保证程序的鲁棒性。
  • 触发场景:文件编码非 UTF-8、程序对目标目录无写入权限、文件已损坏无法读取。
  • 处理逻辑:在read_file()write_result()函数中,通过通用Exception捕获所有未被细分的文件操作异常,输出读取文件失败:{错误原因}写入结果失败:{错误原因},随后退出程序。

对应单元测试样例代码:
import unittest
from main import write_result

class TestExceptionHandle(unittest.TestCase):
def test_write_failed_exception(self):
"""验证写入失败时,程序捕获异常并正常退出"""
# 向非法路径写入,触发文件操作异常
with self.assertRaises(SystemExit) as cm:
write_result('/invalid_system_path/result.txt', 0.85)
self.assertEqual(cm.exception.code, 1)

posted @ 2026-09-15 17:19  梣雨  阅读(10)  评论(0)    收藏  举报