WordCount优化

基本任务

1.Github地址

https://github.com/chaosrings/wcPro

2.PSP表格

PSP2.1

PSP阶段

预估耗时

(分钟)

实际耗时

(分钟)

Planning

计划

 20

 20

· Estimate

· 估计这个任务需要多少时间

 20

 20

Development

开发

 380

 470

· Analysis

· 需求分析 (包括学习新技术)

 20

 30

· Design Spec

· 生成设计文档

 0

 0

· Design Review

· 设计复审 (和同事审核设计文档)

 0

 0

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 30

 30

· Design

· 具体设计

 30

 60

· Coding

· 具体编码

 60

 90

· Code Review

· 代码复审

 60

 60

· Test

· 测试(自我测试,修改代码,提交修改)

 180

 200

Reporting

报告

 100

 90

· Test Report

· 测试报告

 60

 60

· Size Measurement

· 计算工作量

 10

 10

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 30

 20

 

合计

 500

 580

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3.接口实现

我负责输入控制模块的实现。

设计了一个Scanner类,提供以下接口:

无参构造函数和析构函数:

Scanner()
{
}

~Scanner()
{
}

 

主要接口:getString()方法

输入参数是txt文件路径的字符串,返回该文件的内容的字符串。

需求要求只处理txt文件,而不处理其他文件,所以做一个判断即可。

如果是txt文件则返回该文件内容的字符串,否则输出提示语,然后返回空字符串。

string getString(const string &path)
{
	if (path.substr(path.length() - 4, 4) == ".txt")
	{
		ifstream in(path);
		stringstream buffer;
		buffer << in.rdbuf();
		string content(buffer.str());
		return content;
	}
	else
	{
		cout << This is not a ".txg" file !";
	}
	return "";
}

  

4.测试用例设计

只需要测试getString()方法

 

白盒测试:

程序结构简单,只有一个结点,只需设计两个测试用例即可全部覆盖。

测试用例 预期输出 实际输出
test.txt 成功读取出文件内容的字符串 成功读取
test.c 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串

 

 

 

 

黑盒测试:

需求中要求只处理txt文件,我们根据需求等方面来设计黑盒测试。

 

如果只分为txt文件和非txt文件,等价类太少实在设计不出20个测试用例。

我们稍微细分一下

 

  工作路径 其他路径
存在的txt文件 等价类1 等价类2
存在的非txt文件 等价类3 等价类4
不存在的txt文件 等价类5 等价类6
不存在的非txt文件 等价类7 等价类8

 

 

 

 

 

比如我们测试txt文件与数个非txt文件,它们只有文件格式不同,文件内容全部相同。

测试用例 预期输出 实际输出
blacktest.txt 成功读取出文件内容的字符串 成功读取
blacktest.c 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串
blacktest.doc 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串

 

 

 

 

我们测试其他路径下的文件

测试用例 预期输出 实际输出
D:\blacktest.txt 成功读取出文件内容的字符串 成功读取
D:\blacktest.c 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串
D:\blacktest.doc 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串

 

 

 

 

我们测试不存在的文件

测试用例 预期输出 实际输出
notexist.txt 成功读取出文件内容的字符串 成功读取(虽然是空串)
notexist.c 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串
notexist.doc 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串

 

 

 

 

我们测试在其他路径下不存在的文件

 

测试用例 预期输出 实际输出
D:\notexist.txt 成功读取出文件内容的字符串 成功读取(虽然是空串)
D:\notexist.c 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串
D:\notexist.doc 输出“This is not a ".txt" file !”且返回空字符串 输出“This is not a ".txt" file !”且返回空字符串

 

 

 

 

(就算写了很多感觉不必要的测试用例也不知道怎么凑起20个测试用例了)

 

5.单元测试脚本

 白盒测试:

TEST_CLASS(ScannerWhiteBoxTest)
{
private:
	Scanner * scannerTest;
public:
	TEST_METHOD_INITIALIZE(setUp)
	{
		scannerTest = new Scanner();
	}
	TEST_METHOD_CLEANUP(tearDown)
	{
		delete scannerTest;
	}
	TEST_METHOD(TestGetString)
	{
		Assert::AreEqual("For the witcher,Heartless cold.", scannerTest->getString("test.txt"), L".txt fail");

		Assert::AreEqual("", scannerTest->getString("test.c"), L".c fail");
	}
};

 黑盒测试:

TEST_CLASS(ScannerBlackBoxTest)
{
private:
	Scanner * scannerTest;
public:
	TEST_METHOD_INITIALIZE(setUp)
	{
		scannerTest = new Scanner();
	}
	TEST_METHOD_CLEANUP(tearDown)
	{
		delete scannerTest;
	}
	TEST_METHOD(TestGetString)
	{
		Assert::AreEqual("For the witcher,Heartless cold.", scannerTest->getString("blacktest.txt"), L".txt fail");

		Assert::AreEqual("", scannerTest->getString("blacktest.c"), L".c fail");

		Assert::AreEqual("", scannerTest->getString("blacktest.doc"), L".doc fail");

		Assert::AreEqual("For the witcher,Heartless cold.", scannerTest->getString("D:\\blacktest.txt"), L".txt fail");

		Assert::AreEqual("", scannerTest->getString("D:\\blacktest.c"), L".c fail");

		Assert::AreEqual("", scannerTest->getString("D:\\blacktest.doc"), L".doc fail");

		Assert::AreEqual("", scannerTest->getString("notexist.txt"), L".txt fail");

		Assert::AreEqual("", scannerTest->getString("notexist.c"), L".c fail");

		Assert::AreEqual("", scannerTest->getString("notexist.doc"), L".doc fail");

		Assert::AreEqual("", scannerTest->getString("D:\\notexist.txt"), L".txt fail");

		Assert::AreEqual("", scannerTest->getString("D:\\notexist.c"), L".c fail");

		Assert::AreEqual("", scannerTest->getString("D:\\notexist.doc"), L".doc fail");
	}
};

  

运行结果:

WordCount优化_第1张图片

 

扩展任务

1.文档规范

邹欣老师讲义“现代软件工程讲义 3 代码规范与代码复审

如:代码风格规范中谈到,

 

缩进用4个空格比较好。其实这个有点不好接受,虽然我在python中一直习惯用4个空格缩进,这是因为python本身语法的因素。而VS里面会自动的给你用Tab缩进,所以我觉得Tab缩进也没问题吧...

 

行宽必须限制。这是必然的。一行如果太长,观察代码时还需要左右拖动。

在复杂的条件表达式中,用括号清楚地表示逻辑优先级。这样不仅能清楚地表示逻辑优先级,还无需记住逻辑运算符的优先顺序。

每个“{”和“}”都独占一行。虽然是空行,但独占一行能使花括号对齐,容易看。

 

2.评审代码

我对核心处理这一模块进行了评审,按照上述规范。(学号:16072)

token.h :

 

 1 class Lex
 2 {
 3 private:
 4     unsigned int currentPos;
 5     string targetStr;
 6     
 7 public:
 8     Lex(const string & str)
 9     {
10         setTargetStr(str);
11     }
12     Lex()
13     {
14         setTargetStr("");
15     }
16     ~Lex()
17     {
18         targetStr.clear();
19     }
20     void setTargetStr(const string& str)
21     {
22         currentPos = 0;
23         targetStr = "";
24         for (char ch : str)
25         {
26             if (ch < -1 || ch>255)   //特殊字符用`代替。不影响逻辑
27                 targetStr += "`";
28             else if (isalpha(ch))
29                 targetStr += tolower(ch);
30             else
31                 targetStr += ch;
32         }
33     }
34     string getTargetStr()
35     {
36         return targetStr;
37     }
38     static bool cmpByFrequencyDec(const pair<string, int>& p1, const pair<string, int> &p2)
39     {
40         return p1.second > p2.second;
41     }
42     bool finished()
43     {
44         return currentPos == targetStr.size();
45     }
46     string getNextToken()
47     {
48         string thisToken = "";
49         while (currentPos//在currentPos小于目标字符长度时跳过非字母开头
50             ++currentPos;
51         while (currentPos < targetStr.size())
52         {
53             char curChar = targetStr[currentPos];
54             if (isalpha(curChar))        //如果是字母便保存
55                 thisToken += curChar;
56             else if (curChar == '-'&¤tPos < targetStr.size() - 1 && isalpha(targetStr[currentPos + 1]))//有连字符号时,只有连字符号后是字母才算单词
57             {
58                 thisToken += '-';
59             }
60             else
61                 break;  //其他情况,已经从curentPos开始获取到了一个单词,返回
62             currentPos++;
63         }
64         return thisToken;
65     }
66     vectorstring, int> > getWordFreqVec()
67     {
68         unordered_map<string, int>  countMap;
69         while (!finished())
70         {
71             string curToken =getNextToken();
72             if (curToken.size() == 0)
73                 continue;
74             countMap[curToken]++;
75         }
76         vectorstring, int> >  wordFreqVec;
77         wordFreqVec.assign(countMap.begin(), countMap.end());
78         sort(wordFreqVec.begin(), wordFreqVec.end(), cmpByFrequencyDec);
79         return wordFreqVec;
80     }
81     unordered_map<string, int> getWordFreqMap()
82     {
83         unordered_map<string, int> ans;
84         currentPos = 0;
85         vectorstring, int> >  wordFreqVec = getWordFreqVec();
86         for (auto wfPair : wordFreqVec)
87         {
88             ans[wfPair.first] = wfPair.second;
89         }
90         return ans;
91     }
92 };

 

 

在这个模块中,缩进、{}、逻辑表达式、命名都做得很好。

我觉得有问题的地方有以下:

1,第49、56行过长,本来就是很长的代码,再加上注释,都在一行。可以考虑把注释写在上面一行。

2,有些循环或if语句内只有一行语句时,不用{}括起来,由于没有明确的“{”和“}”来判断程序的结构,在有多层控制嵌套的时候,就不容易看清结构和对应关系。如第26,50,54行。

其他的都达到了规范要求,如命名:类Pascal格式(所有单词的第一个字母都大写);函数和变量是lowerCamel格式(第一个单词全部小写,随后单词随Pascal格式)。

 

3.静态检查工具

我采用了cppcheck工具来对代码进行静态检查。

下载地址:http://cppcheck.net/

 

 

4.扫描结果

由于好像不能选择.h文件,于是我把Scanner.h扩展名先改成了.cpp,检查之后再改回去。

WordCount优化_第2张图片

 

 WordCount优化_第3张图片

 

未发现错误。大概是代码简单,易写,容易遵循规范。

我自己的代码里在缩进、空行、{}、逻辑表达式、行宽、命名等方面,因为比较简单的原因,都做到了遵循规范。

 

重新运行单元测试的结果:

WordCount优化_第4张图片

 

小组贡献分:0.26

你可能感兴趣的:(WordCount优化)