Python 单元测试的简单示例

前端之家收集整理的这篇文章主要介绍了Python 单元测试的简单示例前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
对python这个高级语言感兴趣的小伙伴,下面一起跟随编程之家 jb51.cc的小编两巴掌来看看吧!

以前我是不写任何测试的,后来偶尔写单元测试,现在我主动写单元测试 ----- 不得 不承认,测试是有其存在必要性的,要说为什么的话,大概又会引发语言的强弱类型和 是否静态语言之争了吧。

就目前而言,个人认为写单元测试的好处有以下几点:

修改代码之后,单元测试可以保证API不会发生变化(假设原需求就不需API发生 变化)。这点可能一般情况下没什么感觉,但是当你去修改前辈留下的代码的时候, 你就会感谢他写了单元测试,最少让你知道了从功能上,这个函数是干什么的,而且 能保证你修改函数内部实现,但是不影响函数功能

写单元测试的时候会回想函数的作用,从而自动函数进行回想和 review。

缺点嘛:耗费时间。单元测试和文档一样,属于非常重要,但是非常耗费时间的工作, 因为要考虑齐全,考虑到的边界条件越多,测试覆盖率越高,程序越可靠,而想这些东 西是很耗费时间精力的。

吐槽完毕,我们来说说目前我知道的几个和测试有关的东西(全程 Python 3)。

Mock

Mock是个好东西呀,遇到测试中出现的不可预知的或者不稳定因素,就用 Mock 来代 替。例如查询数据库(当然像目前我们用的MongoDB,由于特别灵活,可以直接在代码里 把相应的collection替换掉),例如异步任务等。举个例子:

  1. # @param Python和单元测试那些事儿
  2. # @author 编程之家 jb51.cc|512Pic.com
  3. import logging
  4. from unittest.mock import Mock
  5. logging.basicConfig(level=logging.DEBUG)
  6. # code
  7. class ASpecificException(Exception):
  8. pass
  9. def foo():
  10. pass
  11. def bar():
  12. try:
  13. logging.info("enter function <foo> now")
  14. foo()
  15. except ASpecificException:
  16. logging.exception("we caught a specific exception")
  17. # unittest
  18. def test_foo():
  19. foo = Mock(side_effect=ASpecificException()) # noqa
  20. logging.info("enter function <bar> now")
  21. bar()
  22. logging.info("everything just be fine")
  23. if __name__ == "__main__":
  24. test_foo()
  25. # End www.jb51.cc

运行一下:

  1. root@arch tests: python test_demo.py
  2. INFO:root:enter function <bar> now
  3. INFO:root:enter function <foo> now
  4. INFO:root:everything just be fine
  5. # End www.jb51.cc

一个简单的测试就这么写好了。来,跟我念,Mock 大法好呀!

 

doctest

doctest属于比较简单的测试,写在 docstring 里,这样既能测试用,又能当文档 示例,是在是好用之极啊。缺点是,如果测试太复杂,doctest就显得太臃肿了(例如 如果测试之前要导入一堆东西)。举个例子:

  1. # @param Python和单元测试那些事儿
  2. # @author 编程之家 jb51.cc|512Pic.com
  3. import logging
  4. logging.basicConfig(level=logging.DEBUG)
  5. def foo():
  6. """A utility function that returns True
  7. >>> foo()
  8. True
  9. """
  10. return True
  11. if __name__ == "__main__":
  12. import doctest
  13. logging.debug("start of test...")
  14. doctest.testmod()
  15. logging.debug("end of test...")
  16. # End www.jb51.cc

测试结果:

  1. root@arch tests: python test_demo.py
  2. DEBUG:root:start of test...
  3. DEBUG:root:end of test...
  4. # End www.jb51.cc

unittest

这个文档确实有点长,我感觉还是仔细去读一下文档比较好(虽然我也没读完)。

  1. # @param Python和单元测试那些事儿
  2. # @author 编程之家 jb51.cc|512Pic.com
  3. import unittest
  4. class TestStringMethods(unittest.TestCase):
  5. def setUp(self):
  6. self.alist = []
  7. def tearDown(self):
  8. print(self.alist)
  9. def test_list(self):
  10. for i in range(5):
  11. self.alist.append(i)
  12. if __name__ == '__main__':
  13. unittest.main()
  14. # End www.jb51.cc
  1. root@arch tests: python test_demo.py
  2. [0,1,2,3,4]
  3. .
  4. ----------------------------------------------------------------------
  5. Ran 1 test in 0.001s

 

OK

unittest框架配合上Mock,单元测试基本无忧啦。

 

pytest

上面的单元测试跑起来比较麻烦,当然也可以写一个脚本遍历所有的单元测试文件,然 后执行。不过 pytest 对unittest有比较好的支持

 

pytest默认支持的是 函数 风格的测试,但是我们可以不用这一块嘛(而且很多时候 还是很有用的)。走进项目根目录,输入 pytest 就可以啦。它会自动发现 test_ 开头的文件,然后执行其中 test_ 开头的函数和 unittest 的 test_ 开头的 方法

  1. root@arch tests: pytest
  2. ========================================================= test session starts =========================================================
  3. platform linux -- Python 3.5.2,pytest-3.0.5,py-1.4.31,pluggy-0.4.0
  4. rootdir: /root/tests,inifile:
  5. collected 1 items
  6. test_afunc.py .
  7. ====================================================== 1 passed in 0.03 seconds =======================================================
  8. root@arch tests:
  9. # End www.jb51.cc

总结

编译器没给python做检查,就只有靠我们手写测试了 :(

 

另外其实 pytest 和 unittest 都有很多强大的特性,例如 fixture(不知道 咋翻译好),例如 skip 掉某一部分测试。当然我也是知之甚少,所以还是看文档吧。

猜你在找的Python相关文章