作者 | 豌豆花下猫

责编 | 郭芮

在 Python 中,实现参数化测试的几个库,是如何做到把一个方法变成多个方法,并且将每个方法与相应的参数绑定起来的呢?

我们再提炼一下:在一个类中,如何使用装饰器把一个类方法变成多个类方法(或者产生类似的效果)?

# 带有一个方法的测试类class TestClass:def test_func(self):pass

# 使用装饰器,生成多个类方法class TestClass:def test_func1(self):passdef test_func2(self):passdef test_func3(self):pass

Python 中装饰器的本质就是移花接木,用一个新的方法来替代被装饰的方法。在实现参数化的过程中,我们介绍过的几个库到底用了什么手段/秘密武器呢?

ddt 如何实现参数化?

先回顾一下上篇文章中 ddt 库的写法:

import unittestfrom ddt import ddt,data,unpack@ddtclass MyTest(unittest.TestCase):@data((3, 1), (-1, 0), (1.2, 1.0))@unpackdef test(self, first, second):pass

ddt 可提供 4 个装饰器:1 个加在类上的 @ddt,还有 3 个加在类方法上的 @data、@unpack 和 @file_data(前文未提及)。

先看看加在类方法上的三个装饰器的作用:

# ddt 版本(win):1.2.1def data(*values):global index_lenindex_len = len(str(len(values)))return idata(values)

def idata(iterable):def wrapper(func):setattr(func, DATA_ATTR, iterable)return funcreturn wrapper

def unpack(func):setattr(func, UNPACK_ATTR, True)return func

def file_data(value):def wrapper(func):setattr(func, FILE_ATTR, value)return funcreturn wrapper

它们的共同作用是在类方法上 setattr 添加属性。至于这些属性在什么时候使用?下面看看加在类上的 @ddt 装饰器源码:

第一层 for 循环遍历了所有的类方法,然后是 if/elif 两条分支,分别对应 DATA_ATTR/FILE_ATTR,即对应参数的两种来源:数据(@data)和文件(@file_data)。

elif 分支有解析文件的逻辑,之后跟处理数据相似,所以我们把它略过,主要看前面的 if 分支。这部分的逻辑很清晰,主要完成的任务如下:

  • 遍历类方法的参数键值对

  • 根据原方法及参数对,创建新的方法名

  • 获取原方法的文档字符串

  • 对元组和列表类型的参数作解包

  • 在测试类上添加新的测试方法,并绑定参数与文档字符串

分析源码,可以看出,@data、@unpack 和 @file_data 这三个装饰器主要是设置属性并传参,而 @ddt 装饰器才是核心的处理逻辑。

这种将装饰器分散(分别加在类与类方法上),再组合使用的方案,很不优雅。为什么就不能统一起来使用呢?后面我们会分析它的难言之隐,先按下不表,看看其它的实现方案是怎样的?

parameterized 如何实现参数化?

先回顾一下上篇文章中 parameterized 库的写法:

import unittestfrom parameterized import parameterizedclass MyTest(unittest.TestCase):@parameterized.expand([(3,1), (-1,0), (1.5,1.0)])def test_values(self, first, second):self.assertTrue(first > second)

它提供了一个装饰器类 @parameterized,源码如下(版本 0.7.1),主要做了一些初始的校验和参数解析,并非我们关注的重点,略过。

我们主要关注这个装饰器类的 expand 方法,它的文档注释中写到:

A "brute force" method of parameterizing test cases. Creates new test cases and injects them into the namespace that the wrapped function is being defined in. Useful for parameterizing tests in subclasses of 'UnitTest', where Nose test generators don't work.

关键的两个动作是:“creates new test cases(创建新的测试单元)”和“inject them into the namespace…(注入到原方法的命名空间)”。

关于第一点,它跟 ddt 是相似的,只是一些命名风格上的差异,以及参数的解析及绑定不同,不值得太关注

最不同的则是,怎么令新的测试方法生效?

parameterized 使用的是一种“注入”的方式:

inspect 是个功能强大的标准库,在此用于获取程序调用栈的信息。前三句代码的目的是取出 f_locals,它的含义是“local namespace seen by this frame”,此处 f_locals 指的就是类的局部命名空间。

说到局部命名空间,你可能会想到 locals,但是,我们之前有文章提到过“locals 与 globals 的读写问题”,locals 是可读不可写的,所以这段代码才用了 f_locals。

pytest 如何实现参数化?

按惯例先看看上篇文章中的写法:

import pytest@pytest.mark.parametrize("first,second

python如何输出多个星号_如何将 Python 的一个类方法变为多个方法?相关推荐

  1. python如何输出多个星号_如何使用python输出连续星号?

    小编依稀记得,自己初学编程时候,第一节课,老师就给我们演示了输出连续星号内容,那时候真感叹python的神奇,重温一遍这个内容,入门小伙伴们可以来看下啦~ 有关语法:用嵌套打印小星星 需求 在控制台连 ...

  2. python一行输出多个数据_如何在Python中让两个print()函数的输出打印在一行内?

    1.两个连续的print()函数为什么在输出时内容会分行显示? 解:print()中有两个默认参数sep和end,其中sep是代替分隔符,end是代替末尾的换行符,默认使用','代替空格,且默认末尾加 ...

  3. 如何将 Python 的一个类方法变为多个方法?

    作者 | 豌豆花下猫 责编 | 郭芮 在 Python 中,实现参数化测试的几个库,是如何做到把一个方法变成多个方法,并且将每个方法与相应的参数绑定起来的呢? 我们再提炼一下:在一个类中,如何使用装饰 ...

  4. python同时输出多个值_怎样在python中输出多个数组元素?

    展开全部 如果2113要输出多个列表元素,实际上是列表的分片5261或者说是切片. 以下代码运4102行通过:12list = ['a', 'b', 'mpilgrim', 'z', 'example ...

  5. python如何输出两列数据_如何用python将一列数据分为两列?

    引用来自"Ashkandi"的评论[{'date': c[:10], 'time': c[11:]} for c in Col] 引用来自"vx2008"的评论 ...

  6. python中输出某段文字_怎样用Python提取文本中某一段文字

    展开全部 可以用正则或bai者切片.du 处理大文本用正则,效率高.zhi 简单dao提取的话用切片就行专了. 取出"test"四属个字母,需要找前后的标识符,这里可以看做是&qu ...

  7. python字典默认输出键还是值_说说在 Python 字典中如何在读取不存在的键时得到一个默认值...

    如果有方法能够在 Python 字典类型中,当读取不存在的键时能够得到一个默认值,那么代码就会变得更加直观.通过 defaultdict 类型可以实现这个目的1. 我们来改写一个 "输出单词 ...

  8. 如何用python输出九九乘法表_如何用python输出九九乘法表?有哪些方法?

    大家学了学习python这么久,大概都可以将python融汇贯通使用了吧,今天小编就教大家一个案例,融汇python主要的方法内容,一起来看下吧~ 概述 今天主要介绍如何用Python实现九九乘法表( ...

  9. python如何实时捕捉cmd显示_如何从Python脚本中捕获Python解释器和/或CMD.EXE的输出? -问答-阿里云开发者社区-阿里云...

    如果您正在谈论python解释器或CMD.exe,它是您脚本的"父",那么不可能.在每个类似POSIX的系统中(现在你正在运行Windows,看起来可能有一些我不知道的怪癖,YMM ...

最新文章

  1. Linux 受到开发者偏爱的 9 个理由!
  2. 听说用 Lombok 可以早点下班?
  3. c++ 如何获取网络时间_云台山茶旅集团如何四年时间获取十万老人的万千目光...
  4. The Intelligent Investor Feedback
  5. canvas 红包雨_天猫双十一怎么买省钱?京东双十一红包口令淘宝双十一活动攻略...
  6. 负债十五万左右,信用卡十万,网贷四五万,怎么上岸?
  7. sql 删除字段中下划线_SQL基础教程知识点总结
  8. r语言 回归分析 分类变量_R语言进阶之广义线性回归
  9. Gradient-Based Learning Applied to Document Recognition
  10. bigdecimal js 判断等于0_Js BigDecimal实现精确加减乘除运算的方法
  11. csdn下载码怎么用?
  12. c语言程序谭浩强第二章,PDF版本_谭浩强c语言程序设计. 第二章 程序的灵魂-算法...
  13. flask基于保利威做视频认证
  14. C语言编程学习使用auto定义变量的用法
  15. 串口通信基础知识(UART)
  16. Excel:INDEX函数与MATCH函数
  17. 如何改变python的背景颜色_怎样使用python改变背景颜色
  18. linux查看存储类型及型号,linux怎么看内存型号
  19. PLC程序的调试方法及步骤
  20. 离线强化学习(Offline RL)系列3: (算法篇)策略约束 - BRAC算法原理详解与实现(经验篇)

热门文章

  1. 利用正则表达式去除所有html标签,只保留文字
  2. UVA 12063 Zeros and Ones
  3. UVA-673-栈-水题
  4. Android -- Volley解析
  5. 动态生成的DIV加上DWZ后如何分页的问题
  6. CentOS6.3挂载读写NTFS分区
  7. linux c/c++ 原子操作库 atomic atomic_flag 简介
  8. Web Service 开发工具 gSOAP 简介
  9. linux 内存管理 Transparent HugePages 透明大页 简介
  10. linux Makefile 中使用 shell命令