作业要求参照[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2146]
git地址[https://git.coding.net/shishishaonian/four_arithmetic_operation.githttps://git.coding.net/shishishaonian/four_arithmetic_operation.githttps://git.coding.net/shishishaonian/four_arithmetic_operation.githttps://git.coding.net/shishishaonian/four_arithmetic_operation.githttps://git.coding.net/shishishaonian/four_arithmetic_operation.githttps://git.coding.net/shishishaonian/four_arithmetic_operation.git]
2人结对,使用TDD测试框架 (如NUnit, JUnit, cppUnit等)完成本周作业四则运算试题生成的单元测试。
要求1 对每个功能,先给出测试用例,然后再编码功能。请注意把测试用例视为功能需求完成的检验指标。 (40分)
结对伙伴:李文涛
集成环境:Visual Studio 2017
编程语言:C++
测试框架:VS中提供的本机单元测试项目
编写测试用例:
对于程序运行我们给出以下测试:
功能1,功能2
测试用例 | 预期结果 |
f4 | 出现运算表达式,换行打印? |
f4后输入正确的答案 | 答对了你真是个天才 |
f4后输入错误的答案 | 再想想吧,答案似乎是x喔!,x为正确的答案 |
f4后共答20道题 | 你一共答对1道题,共20道题。 |
功能3
测试用例 | 预期结果 |
f4 -c 10 | 按格式正确输入20道题,且有答案 |
f4 -c -10 | 提示题目数量必须是 正整数。 |
f4 -c 1.2 | 提示题目数量必须是 正整数。 |
f4 -c f | 提示题目数量必须是 正整数。 |
功能4
测试用例 | 预期结果 |
f4 -c 10 | 按格式正确输入20道带有分数的题目,且答案是分数 |
对于程序内部的函数我们利用VS中提供的本机单元测试项目编写测试函数进行测试。内容如下:
Is_Equal(a,b);是用来判断两个数是否相等的,也就是判断输入的答案,和试题的答案时候相等。
gcd(a, b);是用来求最大公约数的函数,在化简分数的时候需要用到。
RPNotation(st, ve);是将中缀表达式,转换为后缀表达式,是程序的核心功能。
Correct_Ans(st, correctAns);是根据后缀表达式来求出运算式的结果的。
下面给出部分测试用例的代码:
TEST_METHOD(TestMethod2) { double a = 2.0; double b = 2.0; bool test = Is_Equal(a, b); Assert::AreEqual<bool>(true, test); }
TEST_METHOD(TestMethod4) { int a = -3; int b = 9; int test = gcd(a, b); Assert::AreEqual<int>(3, test); }
TEST_METHOD(TestMethod7) { vector<char>st, ve,pt; string str1 = "3*2+3-4"; for (int i = 0; i <= str1.length(); i++) { ve.push_back(str1[i]); } string str2 = "32*3+4-"; for (int i = 0; i < str2.length(); i++) { pt.push_back(str2[i]); } RPNotation(st, ve); bool flag = true; if (st.size() != pt.size()) flag = false; for (int i = 0; i < st.size(); i++) { if (st[i] != pt[i]) flag = false; } Assert::AreEqual<bool>(true, flag); }
TEST_METHOD(TestMethod8) { vector<char>st; double correctAns; string str1 = "32*3+4-"; for (int i = 0; i < str1.length(); i++) { st.push_back(str1[i]); } Correct_Ans(st, correctAns); Assert::AreEqual<double>(5, correctAns); }
要求2 在博客报告测试用例全部fail 到 全部pass 的过程,报告事实 (fail到修改代码或者测试用例,到pass) 以及收获。 除了最初的框架,测试用例中存在一次性pass没有经过fail的,也报告一次性通过,给出如此优秀地实现了这部分功能的代码。(40分)
程序运行的测试截图
功能1,2
功能3
功能4
程序函数单元测试的截图
测试TestMethod4没有通过,仔细观察我们在求最大公因数的时候,-3和9希望得到3,但是测试没有通过,下面贴一下gcd函数。
int gcd(int a, int b)
{ return (a % b == 0) ? b : gcd(b, a % b); }
查看代码不难发现,其结果的符号是根据a的符号得到的,但有时候结果可能是-3/9,通过程序得到的公因数是-3,结果变成了1/-3,这不是我们想要的答案。所以修改gcd,对参数的绝对值运算,可以解决这一问题。
int gcd(int m, int n)
{ int a = abs(m); int b = abs(n); return (a % b == 0) ? b : gcd(b, a % b); }
给出中缀变后缀表达式的代码。
void RPNotation(vector<char>&st, vector<char>ve) { st.clear(); stack<char>ssign; for (int i = 0; i < ve.size() - 1; i++) { if (ve[i] >= '0'&&ve[i] <= '9') st.push_back(ve[i]); else { if (ssign.empty() || ve[i] == '(') ssign.push(ve[i]); else { if (ve[i] == ')') { while (ssign.top() != '(') { st.push_back(ssign.top()); ssign.pop(); } ssign.pop(); } else { if (ve[i] == '*' || ve[i] == '/') { while (!ssign.empty() && (ssign.top() == '*' || ssign.top() == '/') && ssign.top() != '(') { st.push_back(ssign.top()); ssign.pop(); } ssign.push(ve[i]); } else { while (!ssign.empty() && ssign.top() != '(') { st.push_back(ssign.top()); ssign.pop(); } ssign.push(ve[i]); } } } } } while (!ssign.empty()) { st.push_back(ssign.top()); ssign.pop(); } }
感想:还没开始单元测试时,心里很没有谱,不知道怎么测,看了些往届学长学姐的博客,都看起来很麻烦的样子。后来发现vs自带的测试功能也能测试,但是一样不知道操作方法,去查了使用方法后也是有点云里雾里,只能慢慢摸索,一点一点去尝试,等到把第一个单元测试做完后,后面的单元测试做起来都比较快,有点轻车熟路的感觉。而且单元测试可以测试每一个函数的正确性,就很方便,可以方便地找到出错的地方,然后加以改正。在修改的途中也遇到过一些麻烦,不知道函数哪里出错了,但是既然已知是这个函数出错了,我们就出去单独写了这个函数,看运行结果来判断哪里出了差错。单元测试可以有效地确定出错地点,快速地修正错误,是编写代码时不可缺少的工具。