• 技术文章 >Python技术 >Python高级

    Python和单元测试那些事儿

    silencementsilencement2019-07-17 15:45:10原创3201

    我们来说说目前几个和测试有关的东西(全程 Python 3)。

    Mock

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    import logging

    from unittest.mock import Mock

    logging.basicConfig(level=logging.DEBUG)

    #  code

    class ASpecificException(Exception):

        pass

    def foo():

        pass

    def bar():

        try:

            logging.info("enter function <foo> now")

            foo()

        except ASpecificException:

            logging.exception("we caught a specific exception")

    #  unittest

    def test_foo():

        foo = Mock(side_effect=ASpecificException())  # noqa

        logging.info("enter function <bar> now")

        bar()

        logging.info("everything just be fine")

    if __name__ == "__main__":

        test_foo()

    运行一下

    1

    2

    3

    4

    root@arch tests: python test_demo.py

    INFO:root:enter function <bar> now

    INFO:root:enter function <foo> now

    INFO:root:everything just be fine

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

    doctest

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    import logging

    logging.basicConfig(level=logging.DEBUG)

    def foo():

        """A utility function that returns True

        >>> foo()

        True

        """

        return True

    if __name__ == "__main__":

        import doctest

        logging.debug("start of test...")

        doctest.testmod()

        logging.debug("end of test...")

    测试结果

    1

    2

    3

    root@arch tests: python test_demo.py

    DEBUG:root:start of test...

    DEBUG:root:end of test...

    unittest

    这个文档确实有点长,我感觉还是仔细去读一下文档比较好。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    import unittest

    class TestStringMethods(unittest.TestCase):

        def setUp(self):

            self.alist = []

        def tearDown(self):

            print(self.alist)

        def test_list(self):

            for i in range(5):

                self.alist.append(i)

    if __name__ == '__main__':

        unittest.main()

    输出结果

    1

    2

    3

    4

    5

    root@arch tests: python test_demo.py

    [0, 1, 2, 3, 4]

    .

    ----------------------------------------------------------------------

    Ran 1 test in 0.001s

    OK

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

    pytest

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

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

    1

    2

    3

    4

    5

    6

    7

    8

    root@arch tests: pytest

    ============================================= test session starts ==============================================

    platform linux -- Python 3.5.2, pytest-3.0.5, py-1.4.31, pluggy-0.4.0

    rootdir: /root/tests, inifile:

    collected 1 items

    test_afunc.py .

    ====================================1 passed in 0.03 seconds =======================================================

    root@arch tests:

    总结

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

    另外其实 pytest 和 unittest 都有很多强大的特性,例如 fixture,例如 skip 掉某一部分测试。

    专题推荐:单元测试
    上一篇:Python中lambda表达式的优缺点及使用场景 下一篇:Python正则表达式findall函数详解

    相关文章推荐

    • 小白必看的Python分支、循环和条件• Python3中_和__的用途和区别

    全部评论我要评论

    © 2021 Python学习网 苏ICP备2021003149号-1

  • 取消发布评论
  • 

    Python学习网