你这么厉害,一定只想把“柠檬班”放在首位
▲
前言
大家好,我是小翟,Lime班Python 6的学生。
过去,unittest经常用于socket自动化测试。 后来想获取单个socket的响应时间,就使用了pytest单元测试框架。
虽然收购时间并不准确。
由于 pytest 测试报告的时间是从用例的开始到结束(包括断言),因此实际时间略长于响应时间。
从参考的角度来说,这个时间其实不是很准确,但是还是有价值的。
Pytest 与 ddt 冲突
如果要使用pytest,就不能使用ddt作为数据驱动,否则运行时会抛出异常。
提示@data不是pytest的fixture
这时候就可以使用pytest的参数化,即以下方法:
一般来说,前两个参数 argnames 和 argvalues 使用得最多。
argnames:一个以冒号分隔的字符串,表示一个或多个参数名称或参数列表/元组。
argvalues:是一个列表,让后面的参数argnames依次从中取值进行迭代
这样的话,我们就解决了第一个问题。
即用pytest参数化来代替unittest的数据驱动。
测试报告中的用例名称不规范
我迫不及待地点击运行,突然发现测试报告中的用例名称很糟糕。 这些是什么鬼,为什么这么写?
这样的测试用例名称乍一看让人感觉很乱,因为根本无法分辨出是哪个socket。
如果能用测试用例中case_id对应的值作为用例名就完美了:
当时我的第一个念头就是看一下检测报告的内容。
与该用例名称的元素对应的标签的td。
对应的类属性值为“col-name”。
那你可以去pytest-html的源码看看在哪里吗?
我在其他地方没有找到,但是在plugin.py中找到了。 可以看到我找到了一个,就是我们想要的td标签。
那么另一个参数self.test_id是什么呢?
大胆猜测,应该是td标签对应的文本值。
由于我们要改变td标签的文本值,所以已经猜测是self.test_id对应的值。
接下来只要搜索一下self.test_id是如何定义的,一切就迎刃而解了!
图1:
图2:
图3:
但事情真的有那么简单吗?
请看上图,一共找到了4个self.test_ids。
除了我们刚才要找的那个之外,还有2个与report.nodeid相关的。
有一个与extra_index和test_index相关,report.nodeid可能是report的一个属性。
而前两个参数是两个crate_asset数组,我们可以直接获取这些东西吗?
看到这里,我感觉第一个想法是错误的,至少方向有问题!
想想之前,在做unittest的时候,ddt是通过改变源码来改变用例名称的。
当 ddt 更改时html优化,它在 HTMLTestRunner 中不会更改。
同理,我们推断如果pytest要改变用例的名称,重点应该是参数化,而不是pytest-html的源码。
这样我就得到了第二个想法,查看parametrize()函数的源码。
查看源代码
在查看源码的过程中,无意中看到了另一个函数的定义,如下:
尤其是ids[index] = testid + str(counters[testid])html优化,是不是很熟悉?
对了,这是测试报告中的[data0]、[data1]...
看看计数器是如何定义的。 参数是一个匿名函数lambda,默认从0开始。
看到这里,大概就更清楚了,我们最关心的应该是ids,而ids恰好是parametrize()函数的一个参数。
源码给出的解释是:ids是字符串或可调用字符串的列表。
如果它是字符串列表,则每个字符串对应于argvalues,argvalues是测试id的一部分。
如果没有,将使用手动生成的 ID。 如果是可调用的...
看看这两句话就知道了。 如果为None,则会手动生成用例名称(测试id就是我们所说的用例名称),也就是我们看到的[data0],[data1]....
如果有 100 个用例,那么第 100 个用例的名称是 [data99]。
如果是列表,则列表中每次迭代的值将用作用例名称
现在我们知道如何更改用例名称。
只需将 ids 参数添加到 @pytest.mark.parametrize() 即可。
使用JS优化测试用例名称
经过第二步的优化,我们已经满足了最基本的需求。
也就是说,所需的用例名称必须在测试用例本身中定义,而不是一系列默认生成的值。
但问题又来了。 看看报告最后那长长的名单,实在是不美观。
如何去除背面
TestCases/test_my_requests.py::TestMyRequests::test_send_requests。
首先考虑直接去源码中定位,但是根据以前的经验,源码中的这个字符串可能是某个属性的值,而你能得到的无非就是这些类似于报表的方法。 属性。
更何况,在不了解pytest和pytest-html运行原理的前提下,这无疑是浪费时间
这时候我看到了js,在pytest所在的resources目录下有一个main.js。
我们可以通过js来改变td标签中的文本内容。
您可以在main.js中定义函数change_testName()。
提取字符串
通过 split() 方法提取字符串
TestCases/test_my_requests.py::TestMyRequests::test_send_requests[checkUpdate_normal] 中的 checkUpdate_normal。
当然你也可以使用常规的
pytest-html加载js的原理是,它会将resources目录下的main.js加载到最终的html测试报告中。
这是生成的html报告源代码:
由于我们不需要主动引入js,所以只需要在main.js中定义函数即可,但是发现自定义的js函数不起作用。
这个办法不行,得另想办法。
由于main.js中定义了很多js函数,我们是否可以将自定义的js语句放在已知的函数上。
当然,前提是变量不能重名,不能影响已知函数的功能。
查了一下,发现有一个疑似初始化的函数init()。
所以放在这个函数里比较合适
调整初始化函数
你已经完成了:还剩下什么
运行后发现我们的目的已经达到了,不仅可以得到单个socket的测试时间,还可以调整用例的名称。
比以前漂亮多了。 更改源代码的唯一建议是使用pipenv创建虚拟环境。
因为如果pytest-html在多个项目之间共享的话,一旦pytest-html源码中的js改变了,所有的项目样式都会改变。
为了保持多个项目依赖关系不中断,请使用虚拟环境。
至此,我们的改变就完成了吗?
请仔细看我们添加的js代码:
诚然,当参数化时,这是没有问题的。
但有些场景我们不需要参数化,比如设计一个test_update_normal测试用例
得到的测试报告如下:
你是否有一种很难看的感觉,第三个用例的名称不符合我们的要求。
这是因为参数化生成的用例名称中含有[],所以我们可以使用js来分割[],而没有使用参数化的用例是没有[]的,而这时候调用js时会出现异常会被抛出,这意味着没有任何改变
既然js有异常行为,就应该有相应的方法来捕获异常。
这时候可以使用try...catch,捕获异常,然后为异常添加处理方法
生成的测试报告又如下所示:
这个时候我觉得用例名称不合标准的地方太多了,所以我们改了源码。
不仅要达到基本目的,更重要的是保持源代码的健壮性。
如果更改后的源代码只能在少数情况下使用,那么这样做就等于破坏。
另外,再次尝试在虚拟环境中更改源。
今天的福利
需要socket自动化测试环境搭建学习视频