利用 pytest 玩转数据驱动测试框架

本文选自测试人社区

pytest架构是什么?

首先,来看一个 pytest 的例子:


        def test_a():  
              print(123)

        collected 1 item  
            test_a.py .                                                                                                            [100%]  
                ============ 1 passed in 0.02s =======================

输出结果很简单:收集到 1 个用例,并且这条测试用例执行通过。

此时思考两个问题:

  1. pytest 如何收集到用例的?
  2. pytest 如何把 python 代码,转换成 pytest 测试用例(又称 item) ?

pytest如何做到收集到用例的?

这个很简单,遍历执行目录,如果发现目录的模块中存在符合“ pytest 测试用例要求的 python 对象”,就将之转换为 pytest 测试用例。

比如编写以下 hook 函数:


        def pytest_collect_file(path, parent):  
                print("hello", path)

        hello C:\Users\yuruo\Desktop\tmp\tmp123\tmp\testcase\__init__.py  
            hello C:\Users\yuruo\Desktop\tmp\tmp123\tmp\testcase\conftest.py  
                hello C:\Users\yuruo\Desktop\tmp\tmp123\tmp\testcase\test_a.py

会看到所有文件内容。

如何构造pytest的item?

pytest 像是包装盒,将 python 对象包裹起来,比如下图:

当写好 python 代码时:


        def test_a:  
                print(123)

会被包裹成 Function :

        <Function test_a>

可以从 hook 函数中查看细节:


        def pytest_collection_modifyitems(session, config, items):  
                pass

于是,理解包裹过程就是解开迷题的关键。pytest 是如何包裹 python 对象的?

下面代码只有两行,看似简单,但暗藏玄机!


        def test_a:  
                print(123)

把代码位置截个图,如下:

我们可以说,上述代码是处于“testcase包”下的 “test_a.py模块”的“test_a函数”, pytest 生成的测试用例也要有这些信息:

处于“testcase包”下的 “test_a.py模块”的“test_a测试用例:

把上述表达转换成下图:

pytest 使用 parent 属性表示上图层级关系,比如 Module 是 Function 的上级, Function 的 parent 属性如下:


        <Function test_a>:  
              parent: <Module test_parse.py>

当然 Module 的 parent 就是 Package:


        <Module test_parse.py>:  
              parent: <Package tests>

注意大小写:Module 是 pytest 的类,用于包裹 python 的 module 。Module 和 module 表示不同意义。

这里科普一下,python 的 package 和 module 都是真实存在的对象,你可以从 obj 属性中看到,比如 Module 的 obj
属性如下:

如果理解了 pytest 的包裹用途,非常好!我们进行下一步讨论:如何构造 pytest 的 item ?

以下面代码为例:


        def test_a:  
                print(123)

构造 pytest 的 item ,需要:

  1. 构建 Package
  2. 构建 Module
  3. 构建 Function
    以构建 Function 为例,需要调用其from_parent()方法进行构建,其过程如下图:

从函数名from_parent,就可以猜测出,“构建 Function”一定与其 parent 有不小联系!又因为 Function 的 parent
是 Module :根据下面 Function 的部分代码(位于 python.py 文件):


        class Function(PyobjMixin, nodes.Item):  
                # 用于创建测试用例  
                        @classmethod  
                                def from_parent(cls, parent, **kw):  
                                            """The public constructor."""  
                                                        return super().from_parent(parent=parent, **kw)  
                                                                # 获取实例  
                                                                        def _getobj(self):  
                                                                                    assert self.parent is not None  
                                                                                          
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值