第一次个人编程作业
第一次个人编程作业
| 这个作业属于哪个课程 | 软件工程 |
|---|---|
| 这个作业要求在哪里 | 个人项目作业 |
| 这个作业的目标 | 设计论文查重算法+应用PSP表格+单元测试+ JProfiler 性能分析+Git管理 |
一、GitHub
二、PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 25 | 30 |
| · Estimate | · 估计这个任务需要多少时间 | 10 | 20 |
| Development | 开发 | 300 | 360 |
| · Analysis | · 需求分析 (包括学习新技术) | 60 | 120 |
| · Design Spec | · 生成设计文档 | 30 | 40 |
| · Design Review | · 设计复审 | 10 | 10 |
| · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 15 | 15 |
| · Design | · 具体设计 | 60 | 60 |
| · Coding | · 具体编码 | 240 | 300 |
| · Code Review | · 代码复审 | 60 | 120 |
| · Test | · 测试(自我测试,修改代码,提交修改) | 120 | 360 |
| Reporting | 报告 | 60 | 120 |
| · Test Report | · 测试报告 | 20 | 20 |
| · Size Measurement | · 计算工作量 | 15 | 15 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 30 |
| · 合计 | 1045 | 1620 |
三、计算模块接口的设计与实现过程
1、 算法原理
-
参考资料:simhash算法及原理简介
-
采用SimHash算法:SimHash算法分为 5 个步骤:分词、hash、加权、合并、降维。
-
整体算法流程图:
![]()
-
算法独到之处:
-
SimHash本身属于一种局部敏感哈希算法,它产生的hash签名在一定程度上可以表征原内容的相似度
-
SimHash算法的签名值除了提供原始内容是否相等的信息外,还能额外提供不相等的原始内容的差异程度的信息。
-
相较传统的hash和余弦相似度算法,SimHash算法相对简单、效果又好
-
2、项目结构设计:

3、类和方法设计
-
IOText 类:读取或写入文件
- getText():传入 txt 路径读取 txt 文件,返回读取到的内容
- writeText(): 传入输出内容和输出路径,向指定路径写入指定内容
-
Main 类:调用函数并输出结果
- main(): 主函数,传入参数,输出结果
- Test1(): 传入测试文件路径和输出路径,调用函数输出结果,并向输出路径写入结果
-
SimHash 类:计算文本相似度的核心算法工具类
- simHash(): 程序的关键函数,将文本进行分词,并得到一个 simHash 值。
- hash(): 计算每个分词对应的 hash 值。
- hammingDistance(): 根据 SimHash 算法算出文档的签名值。
- getDistance(): 计算两个签名的海明距离,海明距离越低,相似度越高
- subByDistance(): 计算海明距离在范围内的各块签名的 hash 值,通常认为距离在3以内的视为重复
-
PathInput 类:分别输入测试文件路径和输出路径,输出结果
-
MyTest 类: 测试类
-
关系流程图:
![]()
-
关键函数simHash()流程图:
![]()
四、计算模块接口部分的性能改进
-
内存占用情况:
![]()
-
类占用情况:
![]()
![]()
-
CPU负载
![]()
五、计算模块部分单元测试展示
1.白盒测试:
对原文件的添加、删除、修改、文件不存在或路径错误、文件内容为空等进行测试。
2.测试用例代码:
package paperpass;
import org.junit.jupiter.api.Test;
class MyTest {
String origin = "text2\\orig.txt";
String[] txtPath={
"text2\\orig_0.8_add.txt",
"text2\\orig_0.8_del.txt",
"text2\\orig_0.8_dis_1.txt",
"text2\\orig_0.8_dis_10.txt",
"text2\\orig_0.8_dis_15.txt",
};
String[] htmlPath={
"text\\orig_0.8_del.txt",
"text\\orig_0.8_dis_1.txt", "text\\orig_0.8_dis_10.txt",
"text\\orig_0.8_dis_15.txt",};
String outPath = "output.txt";
Main txtCheck1 = new Main();
/**
*文本测试:
*原文件的添加
*/
@Test
public void addTest(){
txtCheck1.Test1(origin, txtPath[0],outPath);
}
/**原文件的删除*/
@Test
public void delTest(){
txtCheck1.Test1(origin, txtPath[1],outPath);
}
/**原文件的修改*/
@Test
public void dis_1Test(){
txtCheck1.Test1(origin, txtPath[2],outPath);
}
@Test
public void dis_10Test(){
txtCheck1.Test1(origin, txtPath[3],outPath);
}
@Test
public void dis_15Test(){
txtCheck1.Test1(origin, txtPath[4],outPath);
}
/**
* 对 html 进行测试
* */
@Test
public void html1Test(){
txtCheck1.Test1(origin, htmlPath[1],outPath);
}
@Test
public void html2Test(){
txtCheck1.Test1(origin, htmlPath[3],outPath);
}
/**html 和 html 进行测试*/
@Test
public void html3Test(){
txtCheck1.Test1(htmlPath[0], htmlPath[3],outPath);
}
/**
* 测试文本路径错误或不存在
* */
@Test
public void txtPathWrongTest(){
txtCheck1.Test1("text\\orig_del.txt","text2\\orig_dis_15.txt" ,outPath);
}
/**
* 输出文件路径错误或不存在
* */
@Test
public void outPathWrongTest(){
txtCheck1.Test1("text2\\orig_0.8_del.txt","text2\\orig_0.8_dis_10.txt","out_put.txt");
}
/**
* 测试文本为空
* */
@Test
public void emptyTest(){
txtCheck1.Test1("text2\\empty.txt","text2\\orig_0.8_dis_10.txt","output.txt");
}
3.运行结果:

4.耗时:

可以看出,测试 html 耗时比 txt 文本的耗时久
5.测试覆盖率:

六、计算模块部分异常处理说明
1.测试文件不存在或路径输入错误
-
部分代码
![]()
-
测试用例
![]()
-
测试结果
![]()
2.输出文件路径错误或不存在
-
部分代码
![]()
-
测试用例
![]()
-
测试结果
![]()
3.测试文件为空
-
部分代码
![]()
-
测试用例
![]()
-
测试结果
![]()

















浙公网安备 33010602011771号