异常处理,代码测试

参考:Exception

异常处理

# 当我们认为某些代码可能会出错时,就可以用try来运行这段代码,
# 如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,
# 执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。

try:
    re = 10 / int('a')
    # re=10/int('23')
    print('runing')

except ValueError as e:
    print('value error', e)

# Python的错误其实也是class,所有的错误类型都继承自BaseException,
# exception 间有继承关系,子类要先写在父类异常前面,否则异常会被父类捕捉,子类无法捕捉到异常
# 如 UnicodeError父类为ValueError,这里UnicodeError无法捕捉到异常。
except UnicodeError as e:
    print('UnicodeError')

except ZeroDivisionError as e:
    print('ZeroDivisionError', e)

# 如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句
else:
    print('no error')

finally:
    print('finish')

print('do something')

# 使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,即不断上报错误。
# 比如函数main()调用foo(),foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了,就可以处理。
# 不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。

def bar(parm):
    return 10 / int(parm)

def foo():
    try:
        print(bar('a'))
    except BaseException as e:
        print(e)

foo()

# 如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,
# 打印一个错误信息,错误信息为从顶层到底层,然后程序退出.

# 可以用log把错误堆栈打印出来,(log信息与普通print信息会混叠,并不是按程序执行顺序打印)
# 然后分析错误原因,同时,让程序继续执行下去。

import logging

def fun_0(parm):
    if parm == 0:
        # 抛出错误
        raise ValueError('fuck msg')
    return 10 / parm

def fun_1():
    try:
        fun_0(0)
    except Exception as e:

        # 写log文件,level :过滤日志级别,只有达到该级别及以上的才会记录,
        # a:append,w:rewrite,message:由下面的logging.exception/debag/info/...('msg')决定
        logging.basicConfig(level=logging.DEBUG, filename='error.log', filemode='w',
                            format='%(asctime)s -> %(pathname)s->%(filename)s->[line:%(lineno)d] -> %(levelname)s: %(message)s')

        # 加入logging.basicConfig写信息到文件,不加打印到控制台
        # debug->critical严重因依次递增,
        # 日常记录信息
        logging.debug('debug msg')
        logging.info('info msg')
        # 错误信息
        logging.warning('waring msg')
        logging.error('error msg')
        logging.critical('critical msg')

        # 异常栈信息
        logging.exception(e)

        # 记录日志后,可以将异常原样继续上抛。
        # raise
        # 或者把错误细化后上抛。
        # raise ZeroDivisionError

    print('------finish')

fun_1()

# 单元测试
# 说明我们测试的这个函数能够正常工作。如果单元测试不通过,要么函数有bug,要么测试条件输入不正确,总之,需要修复使单元测试能够通过。
# 如果我们对abs()函数代码做了修改,只需要再跑一遍单元测试,如果通过,说明我们的修改不会对abs()函数原有的行为造成影响,
# 如果测试不通过,说明我们的修改与原有行为不一致,要么修改代码,要么修改测试。
# 这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候,可以极大程度地保证该模块行为仍然是正确的。

class My_dict(dict):

    def __init__(self, **kwargs):
        super().__init__(kwargs)

    # A.a式访问
    def __getattr__(self, item):
        try:
            return self[item]
        except KeyError as e:
            raise

    # A.a式设置值
    def __setattr__(self, key, value):
        self[key] = value

import unittest

# 编写一个测试类,从unittest.TestCase继承,
# 以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行

class TestDict(unittest.TestCase):

    # 可以在单元测试中编写两个特殊的setUp()和tearDown()方法。
    # 这两个方法会分别在每调用一个测试方法的前后分别被执行。
    # 可用于做前期准备或者收尾工作
    def setUp(self):
        print('up')

    def tearDown(self):
        print('down')

    def test_init(self):
        # test init
        my_dict = My_dict(A='a', B='b')
        self.assertEqual(my_dict.A, 'a')
        self.assertEqual(my_dict['A'], 'a')
        self.assertTrue(isinstance(my_dict, dict))
        # test attr
        my_dict.C = 'c'
        self.assertEqual(my_dict.C, 'c')
        # test key
        my_dict['D'] = 'd'
        self.assertEqual(my_dict['D'], 'd')

    #异常处理测试
    def test_errors(self):
        my_dict = My_dict(A='a')
        with self.assertRaises(KeyError):
            value = my_dict.B

# 运行单元测试。
if __name__ == '__main__':
    unittest.main()

# 另一种方法是在命令行通过参数-m unittest直接运行单元测试:
# $ python -m unittest mydict_test

文档测试

# 文档测试
# Python内置的“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。
# doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。
# 只有测试异常的时候,可以用...表示中间一大段烦人的输出
#注意命令行与输出间不能有空行,>>>符号后要加一个空格

class My_dict_Doctest(dict):
    '''

    >>> my_dict = My_dict_Doctest(A='a', B='b')

    >>> my_dict.A
    'a'
    >>> my_dict['A']
    'a'

    >>> isinstance(my_dict, dict)
    True

    >>> my_dict.C = 'c'
    >>> my_dict.C
    'c'

    >>> my_dict['D'] = 'd'
    >>> my_dict['D']
    'd'

    >>> my_dict['E']
    Traceback (most recent call last):
      ...
    KeyError: 'E'

    '''

    def __init__(self,**kwargs):
        super().__init__(kwargs)

    #A.a式访问
    def __getattr__(self, item):
        try:
            return self[item]
        except KeyError as e:
            raise

     #A.a式设置值
    def __setattr__(self, key, value):
        self[key]=value

def my_power(x,n):
    '''
    :param x:
    :param n:
    :return:x^n

    >>> my_power(2,3)
    8

    >>> my_power(2,-1)
    0.5

    >>> my_power(2,'a')
    Traceback (most recent call last):
      ...
    ValueError

    '''

    try:
        return x**n
    except Exception as e:
        raise ValueError

if __name__=='__main__':
    import doctest
    doctest.testmod()

猜你喜欢

转载自www.cnblogs.com/huangqiang97/p/11839170.html
今日推荐