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;
    这里写图片描述
    这里写图片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章