第一次个人编程作业
这个作业属于哪个课程 | 广工计院计科34班软工 |
---|---|
这个作业要求在哪里 | 作业要求 |
这个作业的目标 | python完整项目,从github建仓到代码开发、静态分析、性能分析、单元测试的回归 |
Github仓库地址
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 400 | 380 |
· Analysis | · 需求分析 (包括学习新技术) | 30 | 30 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 | 50 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 50 | 50 |
· Design | · 具体设计 | 120 | 120 |
· Coding | · 具体编码 | 60 | 60 |
· Code Review | · 代码复审 | 30 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 30 |
Reporting | 报告 | 90 | 90 |
· Test Repor | · 测试报告 | 30 | 40 |
· Size Measurement | · 计算工作量 | 30 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
· 合计 | 520 | 520 |
二、模块接口的设计和实现
2.1目录结构
目录结构如图。
- text文件夹存放需要查重的文本
- .coverage是测试覆盖率的默认文件
- main.py为主程序,进行论文查重
- profile_output.main是进行性能分析的默认文件
- test_main.py文件是单元测试文件,进行边界情况、异常情况的测试
2.2接口设计
main文件
read_texts_from_folder
函数- 入参:
folder_path
- 返回值:
texts
- 作用:从文件夹中读取文件,并把文件内容写入字典并返回
- 异常处理:遇到异常直接抛出
- 角色:文本读取者
- 入参:
calculate_cosine_similarity
函数- 入参:
texts
- 返回值:
list(texts.keys())[1:], similarities[0]
(解释:返回排除了原始文件的list,以及similarities) - 作用:从
texts
字典中读取文件内容,进行数据的预处理,然后计算余弦相似度 - 异常处理:遇到异常直接抛出
- 角色:计算查重
- 入参:
print_similarity_percentage
函数- 入参:
texts, similarities
- 返回值:无
- 作用:打印查重结果
- 异常处理:通常不会发生异常
- 角色:打印结果
- 入参:
main
函数- 整合前几个函数运行
test_main文件
test_cosine_similarity_with_mocked_file
- 作用:测试mock文件
test_folder_not_exist
- 测试文件不存在的情况
test_empty_files
- 测试空文件
test_files_with_english_characters
- 测试英文字符的文件
test_files_with_same_content
- 测试相同的文件
test_files_with_different_content
- 测试不同的文件
test_file_with_special_characters
- 测试含有特殊字符的文件
test_file_with_newline
- 测试有换行符的文件
test_file_with_null_bytes
- 测试无字节的文件
test_file_path_error
- 测试路径错误
2.3解释函数
可以知道main
函数线性调用read_texts_from_folder
,calculate_cosine_similarity
,print_similarity_percentage
函数,函数解释在上文,不必画出流程图。
2.4算法关键、独到之处
关键:调用了机器学习库sklearn中的计算余弦相似度的算法,该算法在业内通用且较为认可。
独到:项目目录比较合理,代码组织合理,导入合理,如文件使用相对路径,避免用户调用不了。
2.5代码静态分析
我已经消除了所有的错误、警告、提示信息。
三、模块接口的性能改进
使用的性能分析工具是cProfile
从这些数据中,我们可以看到 main
函数的累积时间相对较高,为 0.016 秒。这可能意味着 main
函数中的代码或者它调用的函数可能存在性能瓶颈。由于main函数是调用其他函数实现的,所以需要分析它调用的其他函数calculate_cosine_similarity
(花费0.004秒)和 read_texts_from_folder
(花费0.001秒)。
着手分析main函数
main函数有四句,其中调用了三个函数。
首先,我们发现,folder_path变量存储无意义,因为这个函数只调用了一次这个变量,不存在简写的情况,所以folder_path变量可以优化。
接着,分析read_texts_from_folder函数
是读取文件夹进行扫描的函数,其中if判断结尾虽然可以优化掉(人为控制text文件夹里面的文件资源),但并无很大的优化意义(因为这个函数只消耗0.001秒,且这个if是保障安全为前提的)。
接着,分析calculate_cosine_similarity
函数
会发现,第一个原始文件会被重复查重,意思是会进行一次原始文件对比原始文件的查重,我们知道,这比较花费时间,可以优化,优化方案是跳过原始文件比较原始文件。
最后,由于上面列表中,print_similarity_percentage
函数的消耗的时间不多,可以忽略。不过如果分析,也会发现并无优化可能。
优化后:
可见性能提升较高。
四、模块部分单元测试展示
单元测试共有十个,包含了较多个特殊情况、异常情况。
文件不存在时,会不会程序会不会异常终止。
文件为空时,程序会不会异常终止。
这个项目的用例是中文文本,如果是英文文本能否正常运行。
文件拥有转义字符时,程序会不会异常终止。
说明:构造测试用例的类型即是将文件可能性、文件内容可能性充分考虑。
测试覆盖率截图:
五、异常处理说明
5.1兜底
首先,说明兜底异常处理。
except Exception as e:
print(f"发生预期外的错误: {e}")
5.2常见异常处理
对于不同的函数,准备了一些常见错误。
5.2.1读取文件:文件不存在
except FileNotFoundError as e:
print(f"文件 {folder_path} 找不到: {e}")
测试用例:
5.2.2计算余弦相似度
对计算时,文本类型(中文英文)、文本内容(是否为空、特殊字符、换行符)进行了测试,由于不知道sklearn的错误类型,故使用兜底错误处理。
测试用例: