第七讲 调试
测试
测试是为了找出代码中的错误,调试是通过错误修改代码使其达到预期的效果
通过将代码分解成独立的模块,从而进行独立的测试和调试。
代码设计好之后,就需要进行测试。
为了测试,需要:
1, 确保代码可以运行
2, 摸索出一套预期的结果,对于一个特定的输入,程序的输出是什么
测试方法:
将输入分解成一系列子集,并且保证每个元素都在一个子集里。然后构建一个测试集,其中少包含每个子集中的一个元素。从每一个子集中,我们挑选一个输入元素,然后运行测试,看它能否成功运行。
测试方法分为两类:
1, 通过特定分类使用启发式的方法探索路径。我们称之为黑盒测试。
2, 基于代码本身使用启发式方法探索路径。我们称之为白盒测试。
黑盒测试 :
黑盒,即一个表面全黑的盒子,因此我们看不到它的里面。因此,事实上,这个检测套件的设计使人们无需查看代码。它的优点在于实施者以外的其他人也可以使用它进行测试。
具体方式:根据函数接受的数据,将输入分解成一系列子集,明确边界情况,对每一个输入子集及边界情况至少检测一次。
白盒测试 :
白盒,意味着我们可以看到代码的内容,白盒测试使用代码本身来引导测试用例的设计,这是一个更全面的手段,它可以找出存在潜在错误的地方,白盒测试也被称作穷举路径测试,其中代码的每一条可能路径至少都被检测了一次。
具体方式:根据函数的所有执行路径,将输入分解成一系列子集,明确边界情况,对每一个输入子集及边界情况至少检测一次。对于循环,可以分为0次,1次, 多次的情况。
测试将从单元测试入手,单元测试会选择一个模块,比如说一个函数,然后检测它。
以确保该模块运行良好。这里就就会抓住一些算法错误,这些就是我会遇到错误的地方,要么 会发生在编写算法时,要么会发生在思考该代码的时候。发现错误并修改,然后重新测试,直到模块正常运行。完成了对模块的检验之后,接着进行集成测试,以检验作为整体的系统是否工作正常如果我们有若干个相互作用的函数,我需要确保即便这些模块运行正常,那么整个系统也得工作正常。一般地,这将会抓住所谓的交互错误。这个的意思是说,在一些地方,不正确的数值将会传递给另一个函数。发现错误并修改之后再回头对模块进行单元测试,之后进行集合测试,往复多次,直到我们认为已经抓到了所有可能的错误
调试 :
找到错误可能所在位置的理念是,使用白盒测试和黑盒测试设计检测套件,首先证明
确实有错误出现,然后使用代码本身来发现错误可能的位置。使用通过打印语句查看运行时的变量,使用二分查找来定位错误的具体位置。
第八讲 断言和异常
异常 :
python提供了异常处理:
def divide(x, y): try: #try代码块中的代码如果发生异常会被捕获 result = x / y except ZeroDivisionError, e: #except 是处理异常的代码块,可以指定要处理的异常类型这里是ZeroDivisionError, #如果指定了类型,则只会处理指定类型的异常,当然你可以捕获多个异常 print "division by zero! " + str(e) except TypeError: divideNew(int(x), int(y)) else: # else: 用于没有异常时执行的语句 print "result is", result finally: #finally 中的代码,不管有没有异常都会执行,通常用于关闭文件等操作 print "executing finally clause"
防御式编程:
在处理数据前检测数据的正确性,使用assert 断言,可以很好的限制输入
def avg(grades, weights): assert not len(grades) == 0, 'no grades data' #断言 assert 表达式[,输出语句] 如果表达式为真则继续执行,否则停止程序抛出异常或者输出自定义信息 newgrades = [convertLetterGrade(elt) for elt in grades] return dotProduct(newgrades, weights)/len(newgrades)