使用 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
(本文完)