0x00 Coding
合作伙伴:庞伊凡(201421123011)、赵娅汀(201421123012)
0x01 题目描述
上一周大家为四则运算程序设计了2-3个新功能,本次在隔了一周之后,我们循序渐进地进阶。
0x02 需求分析
把计算模块提取出来,单独创建一个类。针对提取出来的计算类的接口函数做单元测试。
单元测试的意义:
- 减少bug
一个机器,由各种细小的零件组成,如果其中某件零件坏了,机器运行故障。必须保证每个零件都按设计图要求的规格,机器才能正常运行。一个可单元测试的工程,会把业务、功能分割成规模更小、有独立的逻辑部件,称为单元。单元测试的目标,就是保证各个单元的逻辑正确性。单元测试保障工程各个“零件”按“规格”(需求)执行,从而保证整个“机器”(项目)运行正确,最大限度减少bug。
- 快速定位bug,减少调试时间
如果程序有bug,我们运行一次全部单元测试,找到不通过的测试,可以很快地定位对应的执行代码。修复代码后,运行对应的单元测试;如还不通过,继续修改,运行测试.....直到测试通过。
对于Android项目,要测试某个功能点,不用单元测试的话,必须运行在真机、模拟器上,慢慢debug找到问题点。运行程序到真机,快则半分钟,慢则几分钟。junit只需在本地运行即可,就几秒的事(robolectric需要十几秒)。有时,写那个功能模块的员工已离职,APP运行出错(逻辑错误,非crash or exception),你根本就不知道调试哪个类。如果离职的员工之前写了单元测试,运行一下立马就找到问题点了。单元测试大大减少调试时间,从而达到节约时间成本的效果。
- 提高代码质量
由于每个单元有独立的逻辑,做单元测试时需要隔离外部依赖,确保这些依赖不影响验证逻辑。因为要把各种依赖分离,单元测试会促进工程进行组件拆分,整理工程依赖关系,更大程度减少代码耦合。这样写出来的代码,更好维护,更好扩展,从而提高代码质量。
- 放心重构
重构,每个开发者都会经历,重构后把代码改坏了的情况并不少见。以往,写完一个框架,运行APP,没什么问题,完事。由于最初的框架并不是你写的,可谓牵一发动全身,你改1个方法导致整个框架运行失败....
如果你有单元测试,情况大不相同。写完一个类,把单元测试写了,确保这个类逻辑正确;写第二个类,单元测试.....写100个类,道理一样,每个类做到第一点“保证逻辑正确性”,100个类拼在一起肯定不出问题。你大可以放心一边重构,一边运行APP;而不是整体重构完,提心跳胆地run。
测试内容:
加减乘除功能测试
输入非法字符测试
除0错误测试
0x03 测试框架设计&模拟测试数据
- 加减乘除测试
def test_add(self): #测试加法
que=[[2,'+',4],[3.0,'+',5.0],[10,'+',4],[10,'+',2.0],[25,'+',2.0]]
ans=['6','8.0','14','12.0','27.0']
for i in range(len(que)):
test=calc.operate(que[i][0],que[i][1],que[i][2])
self.assertEqual(test, ans[i])
def test_sub(self): #测试减法
que=[[2,'-',4],[3.0,'-',5.0],[10,'-',4],[10,'-',2.0],[25,'-',2.0]]
ans=['-2','-2.0','6','8.0','23.0']
for i in range(len(que)):
test=calc.operate(que[i][0],que[i][1],que[i][2])
self.assertEqual(test, ans[i])
def test_mult(self): #测试乘法
que=[[2,'*',4],[3.0,'*',5.0],[10,'*',4],[10,'*',2.0],[25,'*',2.0]]
ans=['8','15.0','40','20.0','50.0']
for i in range(len(que)):
test=calc.operate(que[i][0],que[i][1],que[i][2])
self.assertEqual(test, ans[i])
def test_div(self): #测试除法
que=[[2,'/',4],[3.0,'/',5.0],[10,'/',4],[10,'/',2.0],[25,'/',2.0]]
ans=['0','0.6','2','5.0','12.5']
for i in range(len(que)):
test=calc.operate(que[i][0],que[i][1],que[i][2])
self.assertEqual(test, ans[i])
def test_multi(self): #测试多位数
que=['2*3+5-8','3-2/8.0+1','12/4-2.7+5','8*3-6-1.2']
ans=['3','3.75','5.3','16.8']
for i in range(len(que)):
test=calc.operate(que[i])
self.assertEqual(test, ans[i])
将加减乘除分别写在add、sub、mult、div、multi 五个函数里,每个函数内的que列表为测试数据,ans列表为应有的测试结果。
若测试加减乘除功能后得出的结果等于ans列表中的结果,则通过测试,反之则不通过。
- 输入非法字符测试: 输入非法字符,若反馈为'syntax_error',则通过测试。
def test_oper_more_one(self): #测试非法输入
que=[[2,'++',4],[3.0,'---',5.0],[10,'**',4],[10,'////',2.0],[25,'//',2.0]]
ans='syntax_error'
for i in range(len(que)):
test=calc.operate(que[i][0],que[i][1],que[i][2])
self.assertEqual(test, ans)
- 除0错误测试: 进行除法计算时,若除数为0,则反馈为'zero_error',通过测试。
def test_zero(self): #测试除数为0情况
que=[[2,'/',0],[3.0,'/',0],[10,'/',0]]
ans='zero_error'
for i in range(len(que)):
test=calc.operate(que[i][0],que[i][1],que[i][2])
self.assertEqual(test, ans)
- 单元测试结果展示
- 怎么告诉函数的调用者 “你错了”? 把返回的字符串定义为 “-1” 来表示?
语法错误:返回syntax_error
除零错误:返回zero_error
其它错误:返回error
-
那么如果真的计算结果是 “-1” 又怎么处理呢?
因为没有用-1 所以不会出现这个问题的错误。
0x04 覆盖率测试
本次代码使用python编程,选择了coverage
插件进行测试
1. 安装: easy_install coverage
2.测试: coverage run test_operation.py
3.结果展示: coverage report
0x05 结对过程
1. 结对编程感受
这是我们第二次使用结对编程的合作模式,在我们还没有接触结对编程的时候,我们都认为两个人一起做一个项目,就应该是一个人负责实现这几种功能,另一个人负责实现另外几种功能,最后再将这些功能合并到一起,就形成我们俩一起合作完成的项目。在我做领航员的时候,队友敲代码,我会指点她哪里可能出错,用什么方法实现比较好。在队友做领航员的时候,她能很好地提醒我怎么正确地调用函数。这样是极好的!
2. 测试过程遇到的问题以及解决方案
- 在获取两个数值和符号的过程中,一直在报错
TypeError: operate() takes exactly 3 arguments (1 given)
,后来更换了函数调用方法 完成了结果。 - 比较的过程中,需要保持数据类型相同。以前吃过类似的亏,所以解决起来相对比较快速。
3. 评价队友---给队友一个汉堡包
- 先给一片面包:在结对编程的时候发现我的队友还是特别认真的,遇到要实现的功能实现不了,就会一直查资料,百度等等,一定要把它做出来为止才算完。
- 再给一块肉:队友的基础不是很好,一些逻辑过程需要反复交流才能达到想要的效果
- 再给一个面包:总体来说,队友的表现还是非常好的,非常负责,非常认真,我希望她能以后对编程产生兴趣,更有感觉。