3

.py | Python 测试笔记

 6 months ago
source link: https://mountaye.github.io/blog/articles/Python-test-notes
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

晚饭后,绍琳和丈夫送叶文洁和孩子走了很远,副部长说要和叶文洁说句话,绍琳就先回去了。这时,副部长的脸色一瞬间由温暖的微笑变得冷若冰霜,像不耐烦地扯下一副面具,他说:“以后欢迎你带孩子常来,但有一条,不要来追究历史旧账。对于你父亲的死,你母亲没有责任,她也是受害者。倒是你父亲这个人,对自己那些信念的执著有些变态了,一条道走到黑,抛弃了对家庭的责任,让你们母女受了这么多的苦。”

——刘慈欣《三体1.26 无人忏悔》

阿掖山 © 2023
Rights Reserved
Theme by MountAye

阿掖山.py | Python 测试笔记

.py | Python 测试笔记

MountAye

Oct 16, 2023


调试和测试

调试一般是由代码的作者进行,用于自行检查程序运行过程,是否存在思路和实现不匹配的错误,调试的代码一般和程序主体写在一起,主要包括错误处理和日志记录。简单的可以用 print 和 assert,复杂的程序可以用 logging。

测试一般由第三方进行,测试代码和程序代码分离,写测试的人甚至不需要理解程序的具体工作原理,只关注给定的输入能否得到程序宣称的输出。

对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

检验的方法是写一堆测试用例,把测试员拍脑袋想的输入交给相应的模块,看模块的输出是否正确;以及不合理的输入是否被程序识别,抛出异常。

单元测试全通过了不代表程序整体一定就没错误,但是单元测试通不过的程序一定有问题。

文档是对代码的功能介绍,其中不免要举例子,给出实例代码和相应的输出,这个过程很像是单元测试,只不过是纯嘴炮。

文档测试就是自动寻找文档中的示例代码,运行之后,和文档中的结果进行比对。

集成测试模拟用户的行为,测试各个模块之间的配合,测试结果应该保证程序可以在生产环境中工作。

Python 中的测试

上一篇文章里面提到了 src-layout,在 setuptools 的官方文档里提供了一篇博客文章,里面提到,这种文件结构的一个优点就是,测试代码的文件夹一般和 src/ 而不是 package 平级,这就导致运行测试的时候只能先(在虚拟环境里)安装待测试的包,而不会无意中出现测试的代码和用户下载到的内容不同的问题。

<project_name>
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│   └── <package_name>/
│       ├── __init__.py
│       └── example.py
└── tests/

单元测试·unittest

unittest 是 Python 自带的单元测试库。

测试脚本的内容基本如下:

import unittest

class TestName1(unittest.TestCase):

    def test_sum(self):
        self.assertEqual(sum([1, 2, 3]), 6, "Should be 6")

    def test_sum_tuple(self):
        self.assertEqual(sum((1, 2, 2)), 6, "Should be 6")

class TestName2(unittest.TestCase):

    def test_sum(self):
        self.assertEqual(sum([1, 2, 3]), 6, "Should be 6")

    def test_sum_tuple(self):
        self.assertEqual(sum((1, 2, 2)), 6, "Should be 6")

if __name__ == '__main__':
    unittest.main()
  • 测试用例包装在一个 class 里面,这个 class 继承自 unittest.TestCase
  • 所有测试方法名字以 “test” 开头,能测试的性质有限,都是类自带的方法,以 self. 开头。支持的方法见下表,感觉 [assertTrue(x)](https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertTrue)assertRaises(Exception) 包打一切
  • 作为 '__main__' 运行,运行的是自带的函数 unittest.main()
  • 运行时需要 python 指明脚本的文件名。安装了 nose2 这个库的话,可以直接运行 python -m nose2, 它会自动寻找所有的测试依次运行。(后面发现 unittest 好像也有自动发现功能)

https://www.liaoxuefeng.com/wiki/1016959663602400/1017605739507840

Python 的文档测试用的是 doctest 库,写法如下:

class Dict(dict):
    '''
    Simple dict but also support access as x.y style.

    >>> d1 = Dict()
    >>> d1['x'] = 100
    >>> d1.x
    100
    >>> d1.y = 200
    >>> d1['y']
    200
    >>> d2 = Dict(a=1, b=2, c='3')
    >>> d2.c
    '3'
    >>> d2['empty']
    Traceback (most recent call last):
        ...
    KeyError: 'empty'
    >>> d2.empty
    Traceback (most recent call last):
        ...
    AttributeError: 'Dict' object has no attribute 'empty'
    '''
    def __init__(self, **kw):
        super(Dict, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

if __name__=='__main__':
    import doctest
    doctest.testmod()

在保持 docstring 缩进的前提下,>>> 开头的注释会被当作测试运行,紧随其后的行将作为对比基准。只有当预期报错的时候,可以用 ... 省略中间的报错信息。

也可以用 unittest 完成。

和单元测试的区别在于,一般来说需要构建测试数据集等等。这需要重写 unittest.TestCase.setup()

class TestComplexData(unittest.TestCase):
    def setUp(self):
        # load test data
        self.app = App(database='fixtures/test_complex.json')

    def test_customer_count(self):
        self.assertEqual(len(self.app.customers), 10000)

    def test_existence_of_customer(self):
        customer = self.app.get_customer(id=9999)
        self.assertEqual(customer.name, u"バナナ")
        self.assertEqual(customer.address, "10 Red Road, Akihabara, Tokyo")

if __name__ == '__main__':
    unittest.main()

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK