平時在做自動化測試的時候,腳本里面會經常用到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;