WordCountPro 编码与测试
WordCountPro
github项目地址:https://github.com/handsomesnail/WordCountPro
PSP表格
PSP2.1 | PSP阶段 | 预估耗时(小时) | 实际耗时(小时) |
Planning | 计划 | 0.5 | 0.5 |
Estimate | 估计任务需要多少时间 | 0.5 | 0.5 |
Development | 开发 | 2 | 1.5 |
Analysis | 需求分析 | 0.5 | 0.5 |
Design Spec | 生成设计文档 | 0.5 | 0 |
Design Review | 设计复审 | 0.5 | 0.5 |
Coding Standard | 代码规范 | 0.5 | 0.5 |
Design | 具体设计 | 0.5 | 0.5 |
Coding | 具体编码 | 1 | 1 |
Code Review | 代码复审 | 0.5 | 0.5 |
Test | 测试 | 2 | 1.5 |
Reporting | 报告 | 0.5 | 0.5 |
Test Report | 测试报告 | 1 | 0.5 |
Size Measurement | 计算工作量 | 0.5 | 0.5 |
Postmortem | 总结 | 0.5 | 0.5 |
合计 | 11.5 | 9.5 |
基本任务
- 接口实现
在WordCountPro中,我主要负责输入控制模块,本项目直接在main函数中进行输入控制,对输入参数进行有效性校验,识别和处理无效输入,并从中提取所需读取并进行统计的文件路径。输入控制模块关键在于如何获取命令行的参数,以及对参数的处理判别。在Wordcount项目中已经知道main函数参数中的argc 代表参数数量,argv为参数的字符串数组。将argv数组中的参数逐个取出判别,便可获得命令行输入参数以及指定的输入文件名和指定的输出文件名。所以只需要根据本项目的特点改进一下,main函数参数中的argc 代表参数数量,argv为参数的字符串数组。将argv数组中的参数逐个取出判别,便可获得命令行输入参数以及指定的输入文件名和指定的输出文件名。代码如下:
int main(int argc, char *argv[]) { string path = ""; if (argc != 2) { cout << "Please input correct parameter." << endl; return -1; } if (strcmp(argv[1], "-x") == 0) { if (path == "") return -3; } else { path = argv[1]; int fileNamelength = strlen(argv[1]); if (strcmp(argv[1] + fileNamelength - 3, "txt") != 0) { cout << "Please input correct parameter." << endl; return -2; } } return 0; }
- 测试用例设计
对测试用例进行有效性检验,在本项目中,输入参数的形式为: wcPro.exe [input_file_name] 或 wcPro.exe -x 。所以正确的命令行参数个数为2个,第一个参数为当前所运行的程序名,第二个为我们真正需要的参数,为输入文件名或者附加功能。所以针对此进行判断。若用例输入命令行参数不足2个,函数则返回错误码 -1,针对此设计用例2_1,针对输入参数不为以上形式中的任一个设计用例2_2,针对输入参数个数多于2个设计用例2_3,验证参数正确性设计用例2_4,针对输入文件后缀名必须为 .txt 设计用例2_5, 针对附加功能 -x 设计用例2_6,针对 -x 与文件同时输入设计用例2_7。测试用例如下表:
Test Case ID 测试用例编号 |
Test Item 测试项 (即功能模块或函数) |
Test Case Title 测 试用例标题 |
Test Criticality 重要级别 |
Pre-condition 预置条件 |
Input 输入 | Procedure 操作步骤 | Output 预期结果 | Result 实际结果 |
Status 是否通过 |
Remark 备注 (在此描述使用的测试方法) |
2_1 | 输入控制模块 | 缺少参数测试 | M | 无 | wcPro.exe | 无 | -1 | -1 | 是 | 黑盒测试 |
2_2 | 输入控制模块 | 参数错误测试 | M | 无 | wcPro.exe -a | 无 | -2 | -2 | 是 | 黑盒测试 |
2_3 | 输入控制模块 | 参数过多测试 | M | 无 | wcPro.exe -a test.txt | 无 | -1 | -1 | 是 | 黑盒测试 |
2_4 | 输入控制模块 | 正确参数测试 | H | 无 | wcPro.exe test.txt | 无 | test.txt | test.txt | 是 | 黑盒测试 |
2_5 | 输入控制模块 | 文件后缀名错误测试 | H | 无 | wcPro.exe test.c | 无 | -2 | -2 | 是 | 黑盒测试 |
2_6 | 输入控制模块 | 附加功能-x测试 | H | 无 | wcPro.exe -x | 无 | D:\wordCount\test.txt | D:\wordCount\test.txt | 是 | 黑盒测试 |
2_7 | 输入控制模块 | -x与文件名同时输入测试 | L | 无 | wcPro.exe -x test.txt | 无 | -1 | -1 | 是 | 黑盒测试 |
- 单元测试运行结果
所设计的所有测试用例均通过了测试,并且测试用例运行时间极短,效率符合要求。测试用例覆盖了可能出现的输入情况,并覆盖了该模块的所有分支,出于对手所有可能出现的情况的考虑对有些分支进行了重复测试,但不影响测试的整体效率。单元测试结果符合预期。测试结果如图:
- 小组贡献:经小组讨论结果,在本项目中的小组贡献率为0.3。
扩展任务
- 开发规范
Google之《C++风格指南》指出:如果函数超过 40 行, 可以思索一下能不能在不影响程序结构的前提下对其进行分割. 即使一个长函数现在工作的非常好, 一旦有人对其修改, 有可能出现新的问题, 甚至导致难以发现的 bug. 使函数尽量简短, 以便于他人阅读和修改代码.
即在编写函数时要尽量考虑到函数体的长度,如果该函数实现了非常复杂的功能,导致函数过长,这样会使得代码难以理解阅读,尤其是跨越好几个屏幕的函数,不利于阅读以及修改。所以,尽量将函数体限制 在一个屏幕的大小为好。
- 代码分析
分析17071同学的代码,该同学负责的为核心模块(单词的统计与排序),整个函数体长度约20行,此外还有函数调用,函数简短,符合规范要求,且将功能又细分为几个不同函数,更加简单易懂。作为整个项目的核心模块,该模块简洁易读,符合开发规范。
- 静态代码检查
采用的静态代码检查工具为cppcheck。经cppcheck检查得,代码基本符合规范,提示path变量未被使用过,该变量为其它功能使用,故并没有不符合代码规范的地方。该函数体简短,并且含有适量的注释,代码缩进清晰,并有相应的提示信息,以及返回错误码。但是由于该模块直接在main函数中,导致程序结构不清晰,经小组成员建议,将该模块单独封装为函数,返回输入文件名或错误码,由main函数调用。静态代码检查结果如图:
小组成员代码合并后进行静态代码检查,发现一处指针释放不符合规范,释放数组指针应使用 delete[] ,而代码使用的为 delete ,只释放了该数组的第一个元素,导致内存泄漏。经静态代码检查后已修复。检查结果如图:
- 小组代码存在的问题
小组代码整体来说,项目文件注释代码太少,导致需要通读代码才知道该函数的功能以及某些语句的作用,错误码的意义也不明确,变量名用途不明,须加上注释便于理解和修改。部分问题代码如图:
高级任务
- 测试数据集 经过代码分析,小组成员认为统计大文件可以有效测试性能,采用大文件对项目进行压力测试,对主要性能指标(即处理时长)进行测试和记录(debug测试框架下),小组成员的测试结果为:4878ms
- 同行评审以及性能分析
组内所有成员展开同行评审,经过细致分析代码,一致认为制约程序性能主要在核心模块对单词存储的数据结构以及排序算法。在核心模块中主要因素为当前选择的set和map容器,其内部数据结构为红黑树不够高效,次要因素是频繁调用的函数应当设为内联函数,由负责核心模块的小组成员进行性能优化。
- 性能优化
小组成员将记录分隔符表以及单词表的数据结构改为哈希表,并将有关函数改为内联函数,性能得到优化,同等条件下,测试结果提升为3857ms。
- 软件开发、测试、质量之间的关系
在本项目中,基本任务主要工作为开发阶段,以及进行动态测试,扩展任务进行静态测试以及代码规范化,高级任务针对性能进行优化,提升软件性能。可以体会到软件开发中熟练运用各种测试方法,进行测试以及优化,软件项目的质量便可得到保障并获得提升。