Python-異常處理try(一)

平時在做自動化測試的時候,腳本里面會經常用到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;
    這裏寫圖片描述
    這裏寫圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章