python程序调试和测试区别_Python3 错误、调试和测试

1.错误处理

try:print('try...')

r= 10 / int('2')print('result:', r)exceptValueError as e:print('ValueError:', e)exceptZeroDivisionError: ##最后一个except子句可以忽略异常的名称,它将被当作通配符使用print('ZeroDivisionError:', e)else:print('no error!')finally:print('finally...')print('END')

finally一定会被执行(可以没有finally语句)。

如果一个异常没有与任何的 excep 匹配,那么这个异常将会传递给上层的 try 中。

一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,例如: except(RuntimeError, TypeError, NameError): pass

如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句

Python所有的错误都是从BaseException类派生的,写错误类的时候,可能会其子类也“一网打尽”,注意范围。

捕获错误,可以多层调用。

出错的时候,一定要分析错误的调用栈信息,才能定位错误的位置。

Python内置的logging模块可以非常容易地记录错误信息:

#err_logging.py

importloggingdeffoo(s):return 10 /int(s)defbar(s):return foo(s) * 2

defmain():try:

bar('0')exceptException as e:

logging.exception(e)

main()print('END')

同样是出错,但程序打印完错误信息后会继续执行,并正常退出。

raise 语句有如下三种常用的用法:

raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。

raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。

raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。

如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例:

#err_raise.py

classFooError(ValueError):pass

deffoo(s):

n=int(s)if n==0:raise FooError('invalid value: %s' %s)return 10 /n

foo('0')

只有在必要的时候才定义我们自己的错误类型。如果可以选择Python已有的内置的错误类型(比如ValueError,TypeError),尽量使用Python内置的错误类型。

#err_reraise.py

deffoo(s):

n=int(s)if n==0:raise ValueError('invalid value: %s' %s)return 10 /ndefbar():try:

foo('0')exceptValueError as e:print('ValueError!')raisebar()

raise语句如果不带参数,就会把当前错误原样抛出。

raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)。

在except中raise一个Error,还可以把一种类型的错误转化成另一种类型:只要是合理的转换逻辑就可以

try:10 /0exceptZeroDivisionError:raise ValueError('input error!')

try:

a = input("输入一个数:")

#判断用户输入的是否为数字

if(not a.isdigit()):

raise ValueError("a 必须是数字")

except ValueError as e:

print("引发异常:",repr(e))

print("end")

result:

输入一个数:a

引发异常: ValueError('a 必须是数字')

end

当用户输入的不是数字时,程序会进入 if 判断语句,并执行 raise 引发 ValueError 异常。但由于其位于 try 块中,因为 raise 抛出的异常会被 try 捕获,并由 except 块进行处理。

因此,虽然程序中使用了 raise 语句引发异常,但程序的执行是正常的,手动抛出的异常并不会导致程序崩溃。

除了这个,上面的raise 例子中,执行到raise,就退出了。

2.调试

1.用print()把可能有问题的变量打印出来看看。

2.凡是用print()来辅助查看的地方,都可以用断言(assert)来替代。

deffoo(s):

n=int(s)assert n != 0, 'n is zero!'

return 10 /ndefmain():

foo('0')

assert的意思是,表达式n != 0应该是True,否则,根据程序运行的逻辑,后面的代码肯定会出错。

如果断言失败,assert语句本身就会抛出AssertionError:

$ python err.py

Traceback (most recent call last):

...

AssertionError: nis zero!

启动Python解释器时可以用-O参数来关闭assert。关闭后,你可以把所有的assert语句当成pass来看。

3.logging不会抛出错误,而且可以输出到文件。logging.info()就可以输出一段文本

importlogging

logging.basicConfig(level=logging.INFO)

s= '0'n=int(s)

logging.info('n = %d' %n)print(10 / n)

它允许你指定记录信息的级别,有debug,info,warning,error等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。

logging的另一个好处是通过简单的配置,一条语句可以同时输出到不同的地方,比如console和文件。

4.启动Python的调试器pdb。

import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点:

#err.py

importpdb

s= '0'n=int(s)

pdb.set_trace()#运行到这里会自动暂停

print(10 / n)

运行代码,程序会自动在pdb.set_trace()暂停并进入pdb调试环境,可以用命令p查看变量,或者用命令c继续运行

3.单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

需要引入Python自带的unittest模块.

用到再细查。大体是看懂了。一定要做单元测试。减少测试人员的工作量,也减少很多不必要的错误。

单元测试的测试用例要覆盖常用的输入组合、边界条件和异常。

#-*- coding: utf-8 -*-

importunittestclassStudent(object):def __init__(self, name, score):

self.name=name

self.score=scoredefget_grade(self):#if self.score < 0 or self.score > 100:

#raise ValueError('ValueError')

if self.score >= 60 and self.score < 80:return 'B'

elif self.score >= 80 and self.score <= 100:return 'A'

elif self.score >= 0 and self.score < 60:return 'C'

else:raise ValueError("wrong key")classTestStudent(unittest.TestCase):deftest_80_to_100(self):

s1= Student('Bart', 80)

s2= Student('Lisa', 100)

self.assertEqual(s1.get_grade(),'A')

self.assertEqual(s2.get_grade(),'A')deftest_60_to_80(self):

s1= Student('Bart', 60)

s2= Student('Lisa', 79)

self.assertEqual(s1.get_grade(),'B')

self.assertEqual(s2.get_grade(),'B')deftest_0_to_60(self):

s1= Student('Bart', 0)

s2= Student('Lisa', 59)

self.assertEqual(s1.get_grade(),'C')

self.assertEqual(s2.get_grade(),'C')deftest_invalid(self):

s1= Student('Bart', -1)

s2= Student('Lisa', 101)

with self.assertRaises(ValueError):

s1.get_grade()

with self.assertRaises(ValueError):

s2.get_grade()if __name__ == '__main__':

unittest.main()

4.文档测试

#-*- coding: utf-8 -*-

deffact(n):'''Calculate 1*2*...*n

>>> fact(1)

1

>>> fact(10)

3628800

>>> fact(-1)

Traceback (most recent call last):

File "C:\python\lib\doctest.py", line 1329, in __run

compileflags, 1), test.globs)

File "", line 1, in

fact(-1)

File "C:/Workspace/Document/Private/Code/python/tutorial/study.py", line 917, in fact

raise ValueError()

ValueError'''

if n < 1:raiseValueError()if n == 1:return 1

return n * fact(n - 1)if __name__ == '__main__':importdoctest

doctest.testmod()

Python内置的“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。

doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候,可以用...表示中间一大段烦人的输出。

当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest。所以,不必担心doctest会在非测试环境下执行。

5. warnings

warnings.warn(message, category=None, stacklevel=1, source=None)

发出警告,或者忽略它或引发异常。  有时间或遇见再细看吧。

参考自:廖老师的python3和菜鸟

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值