zoukankan      html  css  js  c++  java
  • Python 日志、调试与单元测试

    使用 logging 模块打印日志

    import logging
    logging.basicConfig(level=logging.INFO)
    """
    logging 共有四个级别:
    logging.INFO
    logging.WARNING
    logging.DEBUG
    logging.ERROR
    """
    
    n = 2
    m = 0
    logging.info(f"n:{n}, m:{m}")
    """
    INFO:root:n:2, m:0
    """
    

    pdb 调试代码

    单步调试

    # pdb_demo.py
    a = 2
    b = 3
    c = a + b
    
    python -m pdb pdb_demo.py
    > /root/note/pdb_demo.py(1)<module>()
    -> a = 2
    (Pdb) l # 查看代码
      1  -> a = 2
      2     b = 3
      3     c = a + b
    [EOF]
    (Pdb) n # 单步运行
    > /root/note/pdb_demo.py(2)<module>()
    -> b = 3
    (Pdb) p a # 查看变量 a
    2
    (Pdb) p b # 查看变量 b,此时还未执行到变量b
    *** NameError: name 'b' is not defined
    (Pdb) n # 单步执行
    > /root/note/pdb_demo.py(3)<module>()
    -> c = a + b
    (Pdb) p b
    3
    (Pdb) n
    --Return--
    > /root/note/pdb_demo.py(3)<module>()->None
    -> c = a + b
    (Pdb) p c
    5
    (Pdb) n
    --Return--
    > <string>(1)<module>()->None
    (Pdb) q # 退出
    

    打断点调试

    # pdb_demo.py
    import pdb
    a = 2
    b = 3
    pdb.set_trace()
    c = a + b
    
    python pdb_demo.py
    > /root/note/pdb_demo.py(5)<module>()
    -> c = a + b
    (Pdb) p a
    2
    (Pdb) p b
    3
    (Pdb) p c
    *** NameError: name 'c' is not defined
    (Pdb) n
    --Return--
    > /root/note/pdb_demo.py(5)<module>()->None
    -> c = a + b
    (Pdb) p c
    5
    (Pdb) n
    

    单元测试

    我们开发的项目会不断迭代,每次迭代既要保证新的功能可以用,还要保证原有功能依然没问题。
    通常我们会编写相应的单元测试,这样在每次迭代后,如果新的代码可以通过所有测试用例,那么新的代码就没问题。

    假如编写了一个继承自 dict,但可以用 . 读取属性,可以用来存储数据的类 Storage

    # demo_storage.py
    class Storage(dict):
    
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
    
        def __getattr__(self, key):
            try:
                return self[key]
            except KeyError:
                raise AttributeError(f"key:{key} not exists")
    
        def __setattr__(self, key, value):
            self[key] = value
    

    单元测试可以这样写:

    # test_storage.py
    import unittest
    from demo_storage import Storage
    
    
    class TestStorage(unittest.TestCase):
    
        def test_init(self):
            """
            测试初始化函数
            """
            st = Storage(
                a = 1,
                b = "test"
            )
            self.assertEqual(st.a, 1) # 断言值相等
            self.assertEqual(st.b, "test")
            self.assertTrue(
                isinstance(st, dict)
            )
        
        def test_key(self):
            """
            测试字典方式取值
            """
            st = Storage()
            st["key"] = "value"
            self.assertEqual(st.key, "value")
    
        def test_attr(self):
            """
            测试点方式取值
            """
            st = Storage()
            st.key = "value"
            self.assertTrue("key" in st)
            self.assertEqual(st["key"], "value")
    
        def test_keyerror(self):
            st = Storage()
            with self.assertRaises(KeyError): # 断言抛出指定异常
                value = st["empty"]
    
        def test_attrerror(self):
            st = Storage()
            with self.assertRaises(AttributeError):
                value = st.empty
    
    if __name__ == "__main__":
        unittest.main()
    

    运行单元测试:

    $ python test_storage.py 
    .....
    ----------------------------------------------------------------------
    Ran 5 tests in 0.000s
    
    OK
    $ python -m unittest test_storage.py 
    .....
    ----------------------------------------------------------------------
    Ran 5 tests in 0.000s
    
    OK
    

    有些业务需要连接数据库,这种情况可以编写 setUp()tearDown() 函数,分别表示测试开始和测试结束要运行的逻辑。

        ...
        def setUp(self):
            print("set_up")
    
        def tearDown(self):
            print("tear_down")
        ...
    

    运行测试效果:

    $ python -m unittest test_storage.py 
    set_up
    tear_down
    .set_up
    tear_down
    .set_up
    tear_down
    .set_up
    tear_down
    .set_up
    tear_down
    .
    ----------------------------------------------------------------------
    Ran 5 tests in 0.000s
    
    OK
    

    (本文完)

  • 相关阅读:
    页面上有10个多选框,实现三个按钮(重置、反选、全选)功能
    鼠标点哪 哪出15*15的圆型div
    es写简单的留言板
    面试准备(3)事件循环
    面试准备(2)async+await的使用与原理
    面试准备(1)重排与重绘和验证码
    vue项目修改el-input样式
    echarts画雷达图详解
    决心
    国庆中秋
  • 原文地址:https://www.cnblogs.com/junsircoding/p/15664934.html
Copyright © 2011-2022 走看看