zoukankan      html  css  js  c++  java
  • 【Python】错误、调试和测试

    【错误处理】

    小结:遇到错误怎么办?

    1、不理它。

    2、捕获它,再抛出。

    3、捕获并处理错误。

    raise

    不懂如何处理错误就直接抛出(raise),交由合适的层次处理,有时候需要自定义错误,但是通常使用Python内置的错误就可以了:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    # 自定义的异常
    class MyError(Exception):
        pass
    
    # 抛出异常的函数
    def f():
        raise MyError('This is my error!')
    
    # 不处理,继续抛
    def f2():
        f()
    
    # 不处理,继续抛
    def f3():
        f2()
    
    print('hi1') # 被打印
    f3()
    print('hi2') # 不会被打印,因为程序因为出错而终止了

    处理机的调用和函数调用的方向刚好相反,因为最终都没有人来处理这个错误,所以错误被一直上抛,直到被Python解释器捕获:

    hi1
    Traceback (most recent call last):
      File "D:labs	est.py", line 21, in <module>
      File "D:labs	est.py", line 18, in f3
      File "D:labs	est.py", line 14, in f2
      File "D:labs	est.py", line 10, in f
    __main__.MyError: This is my error!

    不懂如何处理错误的第二种方式是记录一下再继续抛出,这需要用到“try...except”:

    # 自定义的异常
    class MyError(Exception):
        pass
    
    # 抛出异常的函数
    def f():
        raise MyError('This is my error!')
    
    # 不处理,继续抛
    def f2():
        f()
    
    # 不处理,继续抛
    def f3():
        f2()
    
    print('hi1') # 被打印
    
    try:
        f3()
    except Exception as e:
        print('...mark')
        raise # 原样抛出
    finally:
        print('b')
    
    print('hi2') # 错误没被处理了,程序不再执行

    输出:

    hi1
    ...mark
    b
    Traceback (most recent call last):
      File "D:labs	est.py", line 23, in <module>
      File "D:labs	est.py", line 18, in f3
      File "D:labs	est.py", line 14, in f2
      File "D:labs	est.py", line 10, in f
    __main__.MyError: This is my error!

    (可以观察到finally是无论如何都会在最后被执行的!)

    try...except

    错误一般由底层代码抛出,通常是“他人的代码”,所以更经常写的是try...except别人抛出的错误。

    那么如何自己来处理错误呢?当位于合适的层次的时候我们用“try...except”来处理错误:

    print('hi1') # 被打印
    
    try:
        f3()
    except Exception as e:
        print('a:', e)
    finally:
        print('b')
    
    print('hi2') # 错误被处理了,程序继续执行

    输出情况:

    hi1
    a: This is my error!
    b
    hi2

    测试证明except 父类错误就可以捕获子类错误。

    在try的内部一但raise了错误,如果有except语句将其捕获,那么try语句块的剩余语句是不会被执行的,因此try语句块要设定合适的范围,而不是一次try大量的语块:

    class Error1(Exception):
        pass
    
    try:
        print('1')
        raise Error1('Error1')
        print('2') # 不被执行
        print('3') # 不被执行
    except Exception as e:
        print(e)
    
    print('continue execute')
    1
    Error1
    continue execute

     对于捕获多个错误的情况:

    并不是多个错误都会被捕获,因为一旦raise了第一个错误,try语句块的程序就不会再继续执行了,所以同时抛出多个错误的情况是不存在的,书写多个except语句只是为了逐级排查最终捕获一个错误!

    Python的except语句还可以加上else,如果没有错误将会执行else内的语句。

     

    logging

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    import logging
    
    class Error1(Exception):
        pass
    
    try:
        print('1')
        raise Error1('I make a mistake')
        print('2') # 不被执行
        print('3') # 不被执行
    except Exception as e:
        print('4')
        logging.exception(e)
        print('5')
    
    print('continue execute')
    1
    4
    ERROR:root:I make a mistake
    Traceback (most recent call last):
      File "test.py", line 10, in <module>
        raise Error1('I make a mistake')
    Error1: I make a mistake
    5
    continue execute

    今天遇到了一个问题卡了好一会儿:TabError: inconsistent use of tabs and spaces in indentation。原因是混用了空格和tab(可能是copy代码带来的)。最后删掉重输了一遍就解决了。

    【调试】

    debug的方法:

    1、print

    2、断言:print的升级版。

    3、logging:既可以输出到console,也可以输出到文件、不打断程序执行。

    在使用logging之前还需要在程序头添加一行配置:

    import logging
    logging.basicConfig(level=logging.WARNING)

    level指定了记录信息的级别,分为DEBUG、INFO、WARNING、ERROR。当level指定为DEBUG,记录debug及以上的logging信息,当level指定为INFO,记录info及以上的logging信息,以此类推:

    import logging
    logging.basicConfig(level=logging.DEBUG)
    
    print(1)
    logging.debug('debug:hi')
    logging.info('info:hi')
    logging.warning('warning:hi')
    logging.error('error')
    print(2)

    输出:

    1
    DEBUG:root:debug:hi
    INFO:root:info:hi
    WARNING:root:warning:hi
    ERROR:root:error
    2

    继续修改level的等级:

    logging.basicConfig(level=logging.INFO)
    1
    INFO:root:info:hi
    WARNING:root:warning:hi
    ERROR:root:error
    2

    ...

    logging.basicConfig(level=logging.WARNING)
    1
    WARNING:root:warning:hi
    ERROR:root:error
    2

    ...

    logging.basicConfig(level=logging.ERROR)
    1
    ERROR:root:error
    2

    4、pdb

    在命令行下开启dubug模式(参数要加在文件名前面) :

    $ python -m pdb test.py

    输入n单步执行代码:

    $ python -m pdb test.py
    > d:labs	est.py(3)<module>()
    -> n = 0
    (Pdb) n
    > d:labs	est.py(4)<module>()
    -> print(1)
    (Pdb) n
    1
    > d:labs	est.py(5)<module>()
    -> n = n + 1
    (Pdb)

    随时可以用 p 变量名查看变量:

    > $ test.py(9)<module>()
    -> n = n + 1
    (Pdb) p n
    2

    使用q来退出。

     最后,从某处开始debug的方法:

    import pdb
    
    print(1)
    print(2)
    pdb.set_trace() # 从这里开始进入debug模式。
    print(3)
    print(4)
    print(5)

    直接运行.py程序就可以了。

    ps:一直执行n命令将循环运行程序。

    【单元测试】

    Q1:什么是单元测试?

    Q2:如何进行单元测试?

    A1:单元测试是指对一个模块、一个函数或者一个类来进行正确性检验的测试。

    A2:例如我要检测自己写的sum()函数好不好用。

    def sum(x, y):
        return x + y

    1、首先需要编写测试用例,这需要用到Python自带的unittest模块:

    import unittest
    
    from test import sum
    class TestSum(unittest.TestCase):
    
        def test_func(self):
            self.assertEqual(sum(1, 2), 3)
            self.assertEqual(sum(1, -2), -1)
            self.assertEqual(sum(100, -2), 98)
            self.assertEqual(sum(1001, 110), 1111)

    assertEqual是用于判定两个参数是否相等的函数,unittest模块中还有很多用于检测正确性的函数。 凡是test_xxx在测试的时候都会被运行。

    import unittest
    
    from test import sum
    
    class TestSum(unittest.TestCase):
    
        def test_func(self):
            self.assertEqual(sum(1, 2), 3)
            self.assertEqual(sum(1, -2), 0)
            self.assertEqual(sum(100, -2), 98)
            self.assertEqual(sum(1001, 110), 1111)
        
        def test_func2(self):
            self.assertEqual(sum(1, 2), 3)
            self.assertEqual(sum(1, -2), 0)
            self.assertEqual(sum(100, -2), 90)
            self.assertEqual(sum(1001, 110), 1111)
    
        def test_func3(self):
            self.assertEqual(sum(1, 2), 3)
            self.assertEqual(sum(1, -2), -1)
            self.assertEqual(sum(100, -2), 98)
            self.assertEqual(sum(1001, 110), 1111)
    
        def test_func4(self):
            print('hi~')
            print('#$@#%@#$^%%#$^@@#$^&*')

    2、运行测试用例:

    $ python -m unittest sum_test.py
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    OK
    $ python -m unittest sum_test.py
    FF.hi~
    #$@#%@#$^%%#$^@@#$^&*
    .
    ======================================================================
    FAIL: test_func (sum_test.TestSum)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "D:labssum_test.py", line 9, in test_func
        self.assertEqual(sum(1, -2), 0)
    AssertionError: -1 != 0
    
    ======================================================================
    FAIL: test_func2 (sum_test.TestSum)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "D:labssum_test.py", line 15, in test_func2
        self.assertEqual(sum(1, -2), 0)
    AssertionError: -1 != 0
    
    ----------------------------------------------------------------------
    Ran 4 tests in 0.000s
    
    FAILED (failures=2)

     有时候可能会期待是不是抛出一些错误,可以这么写:

    def test_attrerror(self):
        d = Dict()
        with self.assertRaises(AttributeError):
            value = d.empty # raise AttributeError()

     在测试用例中还可以添加setUp和tearDown函数,这两个函数分别在测试开始时和测试结束时被调用。

    【文档测试】

    1、搭建测试环境。

    def sum(x, y):
        '''
    
        test my sum funtion
        
        
        '''
        return x + y
    
    if __name__ == '__main__':
        import doctest
        doctest.testmod()
    $ python test.py
    
    # 无输出

    2、编写测试代码

    def sum(x, y):
        '''
    
        test my sum funtion
        
        >>> sum(2, 3)
        5
        >>> sum(1, 9)
        10
    
        '''
        return x + y
    
    if __name__ == '__main__':
        import doctest
        doctest.testmod()

    如果代码测试无误就不会有输出。

    如果有错则有类似输出如下:

    $ python test.py
    **********************************************************************
    File "test.py", line 8, in __main__.sum
    Failed example:
        sum(1, 9)
    Expected:
        9
    Got:
        10
    **********************************************************************
    1 items had failures:
       1 of   2 in __main__.sum
    ***Test Failed*** 1 failures.
  • 相关阅读:
    zabbix+grafana使用
    其它工具网址
    IntelliJ IDEA 进行多线程调试
    mac外接显示器 双屏同时滑动问题
    wacher和acl
    zookeeper介绍
    iterm2用法与技巧
    linux下ssh公钥验证的设置和远程登录
    不变模式
    单例模式创建的三种方式
  • 原文地址:https://www.cnblogs.com/xkxf/p/6663499.html
Copyright © 2011-2022 走看看