平时在做自动化测试的时候,脚本里面会经常用到try和except,但是感觉好像对try的用法理解的不是很透彻,今天在这里重新学习下,也分享给大家!
- 大家看一下 try 和 except 的工作原理:
try:
#可能发生异常的代码
<语句>
except <各种异常>,e:
#当try中语句发生异常的时候,就会执行except中的语句
<语句>
也就是说,我们把可能在运行过程中会产生异常的语句写在try中,让except去帮我捕获异常信息,并执行except中的语句。
那么会有疑问,把这种感觉会引发异常的语句放在try里面和外面有什么区别呢?让我们来看一段代码,就会立刻明白两者的区别了!
- 没有try
#encoding=utf-8
print 1
print 1/0
print 2
print 'a'
执行结果如下:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
Traceback (most recent call last):
1
File "D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py", line 4, in <module>
print 1/0
ZeroDivisionError: integer division or modulo by zero
Process finished with exit code 1
这里我们可以看到,代码中,引发异常的语句是 print 1/0,执行到这里的时候,程序报错,后面的 print 2,print ‘a’ 就没有再被执行了,程序运行到 print 1/0 之后就中断了。
- 有try的
#encoding=utf-8
print 'start'
try:
print 1/0
except Exception,e:
print e.message
print 'over'
执行结果如下:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
start
integer division or modulo by zero
over
Process finished with exit code 0
这里我们可以看到,print 1/0 引发的异常,但是由于写在了try里面,就会被except截取到,并打印异常信息,并且后面的print ‘over’语句也还可以执行,不会让程序中断。
看到这里大家应该都知道了两者的区别,对于我来讲我觉得最直观的感受就是把异常语句写在try中的话不会影响后面代码的运行,不会让程序在异常语句处中断。
【注意】
如果except没有捕获到应该捕获的异常信息,那么程序会自动报错,程序中断,效果和没有写在try中一样,后面的语句不会被执行,代码如下:
try:
print 100 / float(number)
except IOError,e:
print traceback.format_exc()
print True
执行结果如下:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
please input a number: 0
Traceback (most recent call last):
File "D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py", line 20, in <module>
print 100 / float(number)
ZeroDivisionError: float division by zero
Process finished with exit code 1
这里我们可以看到啊,我们这里写的except是用来截获IOError的,所以相当于异常没有被截获,所以程序自己报错了,导致后面的代码就不会再被执行了,效果和没有try的效果是一样的。所以,为了避免这样的情况发生,不管写了几个except,最后都要加上万能的Exception,这样就可以捕获所有的异常信息,保证程序不会被中断;
代码如下:
try:
print 100 / float(number)
except IOError,e:
print traceback.format_exc()
except Exception,e:
print traceback.format_exc()
print True
执行结果如下:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
please input a number: 0
Traceback (most recent call last):
File "D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py", line 20, in <module>
print 100 / float(number)
ZeroDivisionError: float division by zero
True
Process finished with exit code 0
这里我们可以看到,写了Exception后,即使IOError截取不到报错信息,Exception也会捕获到异常,这样就不会影响后面代码的正常执行了;
- 再来看一下try–except–else的关系
try是可以和else搭配使用的,但是它们三者的执行顺序是如何的呢?让我们来看下面的代码,就会清楚了!
#encoding=utf-8
import traceback
print 'start'
number = raw_input('please input a number: ')
try:
print 100 / float(number)
except ValueError, e:
print traceback.format_exc()
except ZeroDivisionError, e:
print traceback.format_exc()
except Exception, e:
print traceback.format_exc()
else:
print 'except was not executed , so else was executed'
print 'over'
运行脚本(情况1)—触发except,结果如下:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
start
please input a number: jik
Traceback (most recent call last):
File "D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py", line 8, in <module>
print 100 / float(number)
ValueError: could not convert string to float: jik
over
Process finished with exit code 0
从结果中可以看出,else没有被执行;
我们再来运行脚本(情况2)—不触发except,结果如下:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
start
please input a number: 12
8.33333333333
except was not executed , so else was executed
over
Process finished with exit code 0
从结果中可以看出,else被执行了;
所以得到关于try–except–else三者的执行关系的结论如下:
【当任何一个except都不被触发时,执行完try中的语句,就会执行else中的语句。】
- 悄悄告诉你,try 也是可以嵌套的呦~~~
代码如下:
#encoding=utf-8
import traceback
while 1:
number = raw_input('please input a number: ')
try:
try:
try:
try:
print 100 / float(number)
break
except IOError,e:
print traceback.format_exc()
except ValueError,e:
print traceback.format_exc()
except ZeroDivisionError,e:
print traceback.format_exc()
except Exception,e:
print traceback.format_exc()
print 'ajin , mommy love you'
执行结果如下:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
please input a number: xo
Traceback (most recent call last):
File "D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py", line 9, in <module>
print 100 / float(number)
ValueError: could not convert string to float: xo
please input a number: 0
Traceback (most recent call last):
File "D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py", line 9, in <module>
print 100 / float(number)
ZeroDivisionError: float division by zero
please input a number: 1
100.0
ajin , mommy love you
Process finished with exit code 0
这里我们可以直观的看到,try是可以网上寻找的,本层的except如果捕获不到异常,就会向上面的try中的except去寻找,直到最外层,若最外层Except也没有捕获到,就会程序中断报错,导致后面的代码不会被执行;
- try-except-else-finally的执行关系
前面已经说过了try-except-else的关系,那么finally呢,和他们的关系如何呢?
看一段代码就会理解:
def test04(self):
try:
print 2/0
except Exception,e:
print e.message
else:
print 'else'
finally:
print 'finally'
结果如下:
integer division or modulo by zero
finally
可以看出,出发了except,else 是不被执行的,但是并没影响finally的执行;
再看一段代码:
def test04(self):
try:
print 2/1
except Exception,e:
print e.message
else:
print 'else'
finally:
print 'finally'
结果如下:
2
else
finally
可以看出,没有异常,else被执行,finally也被执行;
所以得出结论:
【finally不管有没有异常,最后都会被执行】
- try–except–raise/print 的区别
来一段代码try–except–print e.message【执行报告输出到txt中】:
#encoding=utf-8
import traceback
import unittest
from HTMLTestRunner import HTMLTestRunner
class test_raise(unittest.TestCase):
def setUp(self):
pass
def test01(self):
try:
print 2/0
except Exception,e:
#这里用的是:print e.message,观察test01的测试报告
print e.message
else:
print 'test01-else'
finally:
print 'test01-finally'
def test02(self):
try:
print 2/0
except Exception,e:
#这里用的是 :raise e,观察test02的测试报告
raise e
else:
print 'test02-else'
finally:
print 'test02-finally'
def tearDown(self):
pass
if __name__=='__main__':
suite=unittest.TestSuite()
suite.addTests([test_raise('test01'),test_raise('test02')])
with open('test_raise.txt','a')as fp:
fp.write('\n')
fp.write('* * * '*8+'测试报告'+'* * * '*8+'\n')
runner=unittest.TextTestRunner(stream=fp,verbosity=2)
runner.run(suite)
我们看一下控制台输出的内容:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
integer division or modulo by zero
test01-finally
test02-finally
Process finished with exit code 0
再看一下txt测试报告中的内容:
* * * * * * * * * * * * * * * * * * * * * * * * 测试报告* * * * * * * * * * * * * * * * * * * * * * * *
test01 (__main__.test_raise) ... ok
test02 (__main__.test_raise) ... ERROR
======================================================================
ERROR: test02 (__main__.test_raise)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py", line 26, in test02
raise e
ZeroDivisionError: integer division or modulo by zero
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (errors=1)
这里可以看到,test01中的except使用的print e.message,这样在测试报告中,这条用例不会报error,而是OK,print的e.message是输出到控制台的,不会再报告中打印;但是test02中的except使用的raise e ,这样在报告中,该条用例的执行结果是Error,raise的报错信息不会在控制台输出,而是会在报告中打印出来;
- 再来一段try–except–raise e的代码【测试报告输出到HTML文件中】
#encoding=utf-8
import traceback
import unittest
from HTMLTestRunner import HTMLTestRunner
class test_raise(unittest.TestCase):
def setUp(self):
pass
def test01(self):
try:
print 2/0
except Exception,e:
#这里用的是:print e.message,观察test01的测试报告
print e.message
else:
print 'test01-else'
finally:
print 'test01-finally'
def test02(self):
try:
print 2/0
except Exception,e:
#这里用的是 :raise e,观察test02的测试报告
raise e
else:
print 'test02-else'
finally:
print 'test02-finally'
def tearDown(self):
pass
if __name__=='__main__':
suite=unittest.TestSuite()
suite.addTests([test_raise('test01'),test_raise('test02')])
with open('HTMLReport.html','w')as fp:
runner=HTMLTestRunner(stream=fp,title='raise e and print e',description='Generated by HTMLTestRunner.',verbosity=2)
runner.run(suite)
控制台输出的结果如下:
C:\Python27\python.exe D:/python/Sat0624KeyWordDriven/keyword_driven_frame/abnormal/demo.py
ok test01 (__main__.test_raise)
E test02 (__main__.test_raise)
Time Elapsed: 0:00:00
Process finished with exit code 0
可以看到,测试用例test01是OK,控制台不会打印print e.message的内容;测试用例test02是E,控制台不打印raise抛出的异常e;
html测试报告的输出结果如下:
这里可以看到,在报告里面,test01的执行结果是pass,但是会打印处print e.message的内容和finally中print的内容;test02的执行结果是error,会打印出raise抛出的异常信息,也会打印出finally的print的内容;
用txt作为报告和HTML作为测试报告的共同特点都是,若except用的是print e.message,那么当测试用例中有异常发生时,用例的执行结果是ok,而不是error,也不会抛出引发异常的位置;若except后面用的是raise,就会在报告中正确的显示用例的执行结果,并且抛出异常信息和发生异常的位置;可以很直观的看出哪条用例执行出错了,和所抛出的异常信息,可以更方便的定位错误信息。
- 所以综上所述,对我自己而言的话,如果用unittest来组织测试用例的执行的情况下,我打算用HTML来生成测试报告,而不是txt,不论是控制台显示的执行结果还是报告里面展示的结果,都更为详细和直观。
- 在写测试脚本的时候,except 后面要用raise,而不是print e.message;