WordCountPro
基本任务:代码编写+单元测试
GitHub项目地址
https://github.com/handsomesnail/WordCountPro
PSP表格
PSP | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
·Estimate | 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 250 | 270 |
·Analysis | 需求分析 (包括学习新技术) | 30 | 20 |
·Design Spec | 生成设计文档 | 20 | 20 |
·Design Review | 设计复审 (和同事审核设计文档) | 20 | 10 |
·Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
·Design | 具体设计 | 30 | 30 |
·Coding | 具体编码 | 60 | 70 |
·Code Review | 代码复审 | 20 | 30 |
·Test | 测试(自我测试,修改代码,提交修改) | 60 | 80 |
Reporting | 报告 | 70 | 80 |
·Test Report | 测试报告 | 30 | 40 |
·Size Measurement | 计算工作量 | 10 | 10 |
·Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 350 | 380 |
接口设计
主要负责了处理图形界面和判断模块
-
bool IsSplitSymbol(char c):
返回当前字符是否为分隔符 -
OpenAFile()
图形界面
//返回是否是分隔符
inline bool IsSplitSymbol(char c) {
return splitSymbolsSet.find(c) != splitSymbolsSet.end();
}
string OpenAFile() {
OPENFILENAME ofn;
TCHAR szFile[MAX_PATH];
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = _T("Txt(*.txt)\0*.txt\0\0");
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// 显示打开选择文件对话框。
if (GetOpenFileName(&ofn)) {
//路径转化为string
int iLen = WideCharToMultiByte(CP_ACP, 0, szFile, -1, NULL, 0, NULL, NULL);
char* chRtn = new char[iLen * sizeof(char)];
WideCharToMultiByte(CP_ACP, 0, szFile, -1, chRtn, iLen, NULL, NULL);
string str(chRtn);
delete[] chRtn;
return str;
}
else {
return "";
}
}
测试用例设计
Test Case ID 测试用例编号 | Test Item 测试项(即功能模块或函数) | Test Case Title 测试用例标题 | Test Criticality重要级别实际耗时(分钟) | Pre-condition预置条件 | Input 输入 | Procedure 操作步骤 | Output 预期结果 | Result实际结果 | Status是否通过计划 | Remark 备注(在此描述使用的测试方法) |
---|---|---|---|---|---|---|---|---|---|---|
3_1 | OpenAFile | 图形界面测试 | H | 无 | 无 | 无 | 正确打开图形界面 | 成功打开图形界面 | 是 | 黑盒测试 |
3_2 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_3 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_4 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_5 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_6 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_7 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_8 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_9 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_10 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_11 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_12 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_13 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_14 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_15 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_16 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_17 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_18 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_19 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
3_20 | IsSplitSymbol | 判断分隔符 | M | 无 | c | 无 | T | T | 是 | 白盒测试 |
设计思路
基于两个大模块,对于图形界面模块和分隔符判断模块能否正确运行进行设计
质量评测
设计的测试用例均通过了测试,且测试用例运行时间短,效率符合要求。测试用例覆盖了可能出现的输入情况,并覆盖了该模块的所有分支,单元测试结果符合预期。
小组贡献率
经过小组内部讨论,贡献率约为0.3
扩展任务:静态测试
开发规范
选用了Google的《C++风格指南》中的规范:“果函数超过 40 行, 可以思索一下能不能在不影响程序结构的前提下对其进行分割。”在编写函数时要考虑到函数体的长度,如果该函数要实现复杂的功能,可能会造成函数过长,这样会使得代码难以阅读。
代码分析
根据规范分析组员中学号为17095的提交代码,该同学负责的模块函数体长度约30行行,函数简短,符合规范要求,且将功能细分为两个不同函数,简单易懂,符合开发规范。
静态代码工具:
- 扫描工具:Cppcheck
- 下载地址:http://cppcheck.net/
- 扫描结果:
- 结果分析:扫描发现源文件WordCountPro.cpp中第117行处的指针chRtn释放内存不匹配导致了内存泄漏, chRtn为字符数组, 改用使用delete[] chRtn;释放其内存,替换原代码中的delete chRtn;
组内评价
小组代码大多代码规范良好,但是项目整体注释内容偏少,需要花费较多精力才能明白某一函数的功能以及某些语句的作用,模块划分不够细致。
高级任务:性能测试和优化
压力测试
小组成员认为统计大文件可以有效测试性能,使用较大的文件对源程序进行压力测试,对程序的主要性能指标(即处理时长,以毫秒计算)进行测试和记录(debug测试框架下)。
测试结果为:4878ms
同行评审
组内所有成员展开同行评审,经过讨论,认为制约程序性能的因素主要在核心模块对单词存储的数据结构以及排序算法上。
在核心模块中主要因素为当前选择的set和map容器,其内部数据结构为红黑树不够高效,次要因素则是是频繁调用的函数应当设为内联函数。
性能优化
小组成员将记录分隔符表以及单词表的set和map容器替换为unordered_map和unordered_set,内部为哈希表。并将有关函数改为内联函数。
同等条件下,优化后测试结果为:3857ms。
作业小结
没有软件开发就没有测试,软件开发提供了软件测试的服务对象。开发和测试都是软件生命周期中的重要组成部分,是软件过程中的重要活动。而软件测试则是保证软件质量的重要手段,熟练运用各种测试方法,进行测试和优化,软件项目的质量便能到保障并得到一定的提升。