包含python测试函数耗时的词条
Python测试框架pytest入门基础
通过官方网站介绍我们可以了解到,pytest是一个非常成熟的全功能的python测试框架,主要有
创新互联公司主要从事成都网站设计、成都做网站、网页设计、企业做网站、公司建网站等业务。立足成都服务娄底,十余年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:13518219792
以下几个特点:
1.直接使用pip命令安装
2.验证安装结果
3.在pytest测试框架中,要遵循以下约束:
pytest进行测试比较简单,我们来看一个实例:
这里我们定义了了两个测试函数,直接打印出结果,下面执行测试:
输出结果中显示执行了多少条案例、对应的测试模块、通过条数以及执行耗时。
pytest断言主要使用Python原生断言方法,主要有以下几种:
可以看到运行结果中明确指出了错误原因是"AssertionError",因为PHP不在str1中。
1.运行指定案例
2.运行当前文件夹包括子文件夹所有用例
3.运行指定文件夹(code目录下所有用例)
4.运行模块中指定用例(运行模块中test_add用例)
5.执行失败的最大次数
使用表达式"--maxfail=num"来实现( 注意:表达式中间不能存在空格 ),表示用例失败总数等于num 时停止运行。
6.错误信息在一行展示
在实际项目中如果有很多用例执行失败,查看报错信息将会很麻烦。使用"--tb=line"命令,可以很好解决这个问题。
本地写一个查询用户信息的接口,通过pytest来调用,并进行接口断言。
Python - pytest
目录
pytest是Python的单元测试框架,同自带的unittest框架类似,但pytest框架使用起来更简洁,效率更高。
pytest特点
安装
测试
在测试之前要做的准备
我的演示脚本处于这样一个的目录中:
踩坑:你创建的pytest脚本名称中不允许含有 . ,比如 1.简单上手.py ,这样会报错。当然,可以这么写 1-简单上手.py
demo1.py :
上例中,当我们在执行(就像Python解释器执行普通的Python脚本一样)测试用例的时候, pytest.main(["-s", "demo1.py"]) 中的传参需要是一个元组或者列表(我的pytest是5.2.2版本),之前的版本可能需要这么调用 pytest.main("-s demo1.py") ,传的参数是str的形式,至于你使用哪种,取决于报不报错:
遇到上述报错,就是参数需要一个列表或者元组的形式,而我们使用的是str形式。
上述代码正确的执行结果是这样的:
大致的信息就是告诉我们:
pytest.main(["-s", "demo1.py"])参数说明
除了上述的函数这种写法,也可以有用例类的写法:
用法跟unittest差不多,类名要以 Test 开头,并且其中的用例方法也要以 test 开头,然后执行也一样。
执行结果:
那么,你这个时候可能会问,我记得unittest中有setup和teardown的方法,难道pytest中没有嘛?你怎么提都不提?稳住,答案是有的。
接下来,我们来研究一下pytest中的setup和teardown的用法。
我们知道,在unittest中,setup和teardown可以在每个用例前后执行,也可以在所有的用例集执行前后执行。那么在pytest中,有以下几种情况:
来一一看看各自的用法。
模块级别setup_module/teardown_module
执行结果:
类级别的setup_class/teardown_class
执行结果:
类中方法级别的setup_method/teardown_method
执行结果:
函数级别的setup_function/teardown_function
执行结果:
小结
该脚本有多种运行方式,如果处于PyCharm环境,可以使用右键或者点击运行按钮运行,也就是在pytest中的主函数中运行:
也可以在命令行中运行:
这种方式,跟使用Python解释器执行Python脚本没有什么两样。也可以如下面这么执行:
当然,还有一种是使用配置文件运行,来看看怎么用。
在项目的根目录下,我们可以建立一个 pytest.ini 文件,在这个文件中,我们可以实现相关的配置:
那这个配置文件中的各项都是什么意思呢?
首先, pytest.ini 文件必须位于项目的根目录,而且也必须叫做 pytest.ini 。
其他的参数:
OK,来个示例。
首先,(详细目录参考开头的目录结构)在 scripts/test_case_01.py 中:
在 scripts/test_case_dir1/test_case02.py 中:
那么,在不同的目录或者文件中,共有5个用例将被执行,而结果则是两个失败三个成功。来执行验证一下,因为有了配置文件,我们在终端中(前提是在项目的根目录),直接输入 pytest 即可。
由执行结果可以发现, 2 failed, 3 passed ,跟我们的预期一致。
后续执行相关配置都来自配置文件,如果更改,会有相应说明,终端都是直接使用 pytest 执行。
我们知道在unittest中,跳过用例可以用 skip ,那么这同样是适用于pytest。
来看怎么使用:
跳过用例,我们使用 @pytest.mark.skipif(condition, reason) :
然后将它装饰在需要被跳过用例的的函数上面。
效果如下:
上例执行结果相对详细,因为我们在配置文件中为 addopts 增加了 -v ,之前的示例结果中,没有加!
另外,此时,在输出的控制台中, 还无法打印出 reason 信息,如果需要打印,则可以在配置文件中的 addopts 参数的 -s 变为 -rs :
如果我们事先知道测试函数会执行失败,但又不想直接跳过,而是希望显示的提示。
Pytest 使用 pytest.mark.xfail 实现预见错误功能::
需要掌握的必传参数的是:
那么关于预期失败的几种情况需要了解一下:
结果如下:
pytest 使用 x 表示预见的失败(XFAIL)。
如果预见的是失败,但实际运行测试却成功通过,pytest 使用 X 进行标记(XPASS)。
而在预期失败的两种情况中,我们不希望出现预期失败,结果却执行成功了的情况出现,因为跟我们想的不一样嘛,我预期这条用例失败,那这条用例就应该执行失败才对,你虽然执行成功了,但跟我想的不一样,你照样是失败的!
所以,我们需要将预期失败,结果却执行成功了的用例标记为执行失败,可以在 pytest.ini 文件中,加入:
这样就就把上述的情况标记为执行失败了。
pytest身为强大的单元测试框架,那么同样支持DDT数据驱动测试的概念。也就是当对一个测试函数进行测试时,通常会给函数传递多组参数。比如测试账号登陆,我们需要模拟各种千奇百怪的账号密码。
当然,我们可以把这些参数写在测试函数内部进行遍历。不过虽然参数众多,但仍然是一个测试,当某组参数导致断言失败,测试也就终止了。
通过异常捕获,我们可以保证程所有参数完整执行,但要分析测试结果就需要做不少额外的工作。
在 pytest 中,我们有更好的解决方法,就是参数化测试,即每组参数都独立执行一次测试。使用的工具就是 pytest.mark.parametrize(argnames, argvalues) 。
使用就是以装饰器的形式使用。
只有一个参数的测试用例
来看(重要部分)结果::
可以看到,列表内的每个手机号,都是一条测试用例。
多个参数的测试用例
(重要部分)结果:
可以看到,每一个手机号与每一个验证码都组合一起执行了,这样就执行了4次。那么如果有很多个组合的话,用例数将会更多。我们希望手机号与验证码一一对应组合,也就是只执行两次,怎么搞呢?
在多参数情况下,多个参数名是以 , 分割的字符串。参数值是列表嵌套的形式组成的。
固件(Fixture)是一些函数,pytest 会在执行测试函数之前(或之后)加载运行它们,也称测试夹具。
我们可以利用固件做任何事情,其中最常见的可能就是数据库的初始连接和最后关闭操作。
Pytest 使用 pytest.fixture() 定义固件,下面是最简单的固件,访问主页前必须先登录:
结果:
在之前的示例中,你可能会觉得,这跟之前的setup和teardown的功能也类似呀,但是,fixture相对于setup和teardown来说更灵活。pytest通过 scope 参数来控制固件的使用范围,也就是作用域。
比如之前的login固件,可以指定它的作用域:
很多时候需要在测试前进行预处理(如新建数据库连接),并在测试完成进行清理(关闭数据库连接)。
当有大量重复的这类操作,最佳实践是使用固件来自动化所有预处理和后处理。
Pytest 使用 yield 关键词将固件分为两部分, yield 之前的代码属于预处理,会在测试前执行; yield 之后的代码属于后处理,将在测试完成后执行。
以下测试模拟数据库查询,使用固件来模拟数据库的连接关闭:
结果:
可以看到在两个测试用例执行前后都有预处理和后处理。
pytest中还有非常多的插件供我们使用,我们来介绍几个常用的。
先来看一个重要的,那就是生成测试用例报告。
想要生成测试报告,首先要有下载,才能使用。
下载
如果下载失败,可以使用PyCharm下载,怎么用PyCharm下载这里无需多言了吧。
使用
在配置文件中,添加参数:
效果很不错吧!
没完,看我大招
Allure框架是一个灵活的轻量级多语言测试报告工具,它不仅以web的方式展示了简洁的测试结果,而且允许参与开发过程的每个人从日常执行的测试中最大限度的提取有用信息。
从开发人员(dev,developer)和质量保证人员(QA,Quality Assurance)的角度来看,Allure报告简化了常见缺陷的统计:失败的测试可以分为bug和被中断的测试,还可以配置日志、步骤、fixture、附件、计时、执行 历史 以及与TMS和BUG管理系统集成,所以,通过以上配置,所有负责的开发人员和测试人员可以尽可能的掌握测试信息。
从管理者的角度来看,Allure提供了一个清晰的“大图”,其中包括已覆盖的特性、缺陷聚集的位置、执行时间轴的外观以及许多其他方便的事情。allure的模块化和可扩展性保证了我们总是能够对某些东西进行微调。
少扯点,来看看怎么使用。
Python的pytest中allure下载
但由于这个 allure-pytest 插件生成的测试报告不是 html 类型的,我们还需要使用allure工具再“加工”一下。所以说,我们还需要下载这个allure工具。
allure工具下载
在现在allure工具之前,它依赖Java环境,我们还需要先配置Java环境。
注意,如果你的电脑已经有了Java环境,就无需重新配置了。
配置完了Java环境,我们再来下载allure工具,我这里直接给出了百度云盘链接,你也可以去其他链接中自行下载:
下载并解压好了allure工具包之后,还需要将allure包内的 bin 目录添加到系统的环境变量中。
完事后打开你的终端测试:
返回了版本号说明安装成功。
使用
一般使用allure要经历几个步骤:
来看配置 pytest.ini :
就是 --alluredir ./report/result 参数。
在终端中输入 pytest 正常执行测试用例即可:
执行完毕后,在项目的根目下,会自动生成一个 report 目录,这个目录下有:
接下来需要使用allure工具来生成HTML报告。
此时我们在终端(如果是windows平台,就是cmd),路径是项目的根目录,执行下面的命令。
PS:我在pycharm中的terminal输入allure提示'allure' 不是内部或外部命令,也不是可运行的程序或批处理文件。但windows的终端没有问题。
命令的意思是,根据 reportresult 目录中的数据(这些数据是运行pytest后产生的)。在 report 目录下新建一个 allure_html 目录,而这个目录内有 index.html 才是最终的allure版本的HTML报告;如果你是重复执行的话,使用 --clean 清除之前的报告。
结果很漂亮:
allure open
默认的,allure报告需要HTTP服务器来打开,一般我们可以通过pycharm来完成,另外一种情况就是通过allure自带的open命令来完成。
allure的其他用法
当然,故事还是没有完!在使用allure生成报告的时候,在编写用例阶段,还可以有一些参数可以使用:
allure.title与allure.description
feature和story
由上图可以看到,不同的用例被分为不同的功能中。
allure.severity
allure.severity 用来标识测试用例或者测试类的级别,分为blocker,critical,normal,minor,trivial5个级别。
severity的默认级别是normal,所以上面的用例5可以不添加装饰器了。
allure.dynamic
在之前,用例的执行顺序是从上到下依次执行:
正如上例的执行顺序是 3 1 2 。
现在,来看看我们如何手动控制多个用例的执行顺序,这里也依赖一个插件。
下载
使用
手动控制用例执行顺序的方法是在给各用例添加一个装饰器:
那么, 现在的执行顺序是 2 1 3 ,按照order指定的排序执行的。
如果有人较劲传个0或者负数啥的,那么它们的排序关系应该是这样的:
失败重试意思是指定某个用例执行失败可以重新运行。
下载
使用
需要在 pytest.ini 文件中, 配置:
给 addopts 字段新增(其他原有保持不变) --reruns=3 字段,这样如果有用例执行失败,则再次执行,尝试3次。
来看示例:
结果:
我们也可以从用例报告中看出重试的结果:
上面演示了用例失败了,然后重新执行多少次都没有成功,这是一种情况。
接下来,来看另一种情况,那就是用例执行失败,重新执行次数内通过了,那么剩余的重新执行的次数将不再执行。
通过 random 模块帮助我们演示出在某次执行中出现失败的情况,而在重新执行的时候,会出现成功的情况,看结果:
可以看到,用例 02 重新执行了一次就成功了,剩余的两次执行就终止了。
一条一条用例的执行,肯定会很慢,来看如何并发的执行测试用例,当然这需要相应的插件。
下载
使用
在配置文件中添加:
就是这个 -n=auto :
并发的配置可以写在配置文件中,然后其他正常的执行用例脚本即可。另外一种就是在终端中指定,先来看示例:
结果:
pytest-sugar 改变了 pytest 的默认外观,添加了一个进度条,并立即显示失败的测试。它不需要配置,只需 下载插件即可,用 pytest 运行测试,来享受更漂亮、更有用的输出。
下载
其他照旧执行用例即可。
pytest-cov 在 pytest 中增加了覆盖率支持,来显示哪些代码行已经测试过,哪些还没有。它还将包括项目的测试覆盖率。
下载
使用
在配置文件中:
也就是配置 --cov=./scripts ,这样,它就会统计所有 scripts 目录下所有符合规则的脚本的测试覆盖率。
执行的话,就照常执行就行。
结果:
更多插件参考:
有的时候,在 pytest.ini 中配置了 pytest-html 和 allure 插件之后,执行后报错:
出现了这个报错,检查你配置的解释器中是否存在 pytest-html 和 allure-pytest 这两个模块。如果是使用的pycharm ide,那么你除了检查settings中的解释器配置之外,还需要保证运行脚本的编辑器配置是否跟settings中配置一致。
python测试type函数验证列表和字典的速度分别是多少
第一段:
if(pos in fre_dist.keys()):
newvalue= fre_dist[pos]
第二段:
if(pos in fre_dist):
newValue=fre_dist[pos]
在处理3万条数据时,第二段代码的速度是第一段代码速度的上千倍。
原因是:第一段代码 fre_dist.keys()变成了list,python在检索list的时候是比较慢的,第二段代码 fre_dist是字典,python在检索字典的时候速度是比较快的。
python测试函数有哪些
测试函数是用于自动化测试,使用python模块中的unittest中的工具来测试
附上书中摘抄来的代码:
#coding=utf-8import unittestfrom name_function import get_formatted_nameclass NamesTestCase(unittest.TestCase): def test_first_last_name(self): formatted_name=get_formatted_name('janis','joplin') self.assertEqual(formatted_name,'Janis Joplin') def test_first_last_middle_name(self): formatted_name=get_formatted_name('wolfgang','mozart','amadeus') self.assertEqual(formatted_name,'Wolfgang Amadeus Mozart')#注意下面这行代码,不写会报错哦~~~书中没有这行if __name__=="__main__": unittest.main()
Python中冷门但非常好用的内置函数
Python中有许多内置函数,不像print、len那么广为人知,但它们的功能却异常强大,用好了可以大大提高代码效率,同时提升代码的简洁度,增强可阅读性
Counter
collections在python官方文档中的解释是High-performance container datatypes,直接的中文翻译解释高性能容量数据类型。这个模块实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择。在python3.10.1中它总共包含以下几种数据类型:
容器名简介
namedtuple() 创建命名元组子类的工厂函数
deque 类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
ChainMap 类似字典(dict)的容器类,将多个映射集合到一个视图里面
Counter 字典的子类,提供了可哈希对象的计数功能
OrderedDict 字典的子类,保存了他们被添加的顺序
defaultdict 字典的子类,提供了一个工厂函数,为字典查询提供一个默认值
UserDict 封装了字典对象,简化了字典子类化
UserList 封装了列表对象,简化了列表子类化
UserString 封装了字符串对象,简化了字符串子类化
其中Counter中文意思是计数器,也就是我们常用于统计的一种数据类型,在使用Counter之后可以让我们的代码更加简单易读。Counter类继承dict类,所以它能使用dict类里面的方法
举例
#统计词频
fruits = ['apple', 'peach', 'apple', 'lemon', 'peach', 'peach']
result = {}
for fruit in fruits:
if not result.get(fruit):
result[fruit] = 1
else:
result[fruit] += 1
print(result)
#{'apple': 2, 'peach': 3, 'lemon': 1}下面我们看用Counter怎么实现:
from collections import Counter
fruits = ['apple', 'peach', 'apple', 'lemon', 'peach', 'peach']
c = Counter(fruits)
print(dict(c))
#{'apple': 2, 'peach': 3, 'lemon': 1}显然代码更加简单了,也更容易阅读和维护了。
elements()
返回一个迭代器,其中每个元素将重复出现计数值所指定次。元素会按首次出现的顺序返回。如果一个元素的计数值小于1,elements()将会忽略它。
c = Counter(a=4, b=2, c=0, d=-2)
sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']most_common([n])
返回一个列表,其中包含n个最常见的元素及出现次数,按常见程度由高到低排序。如果n被省略或为None,most_common()将返回计数器中的所有元素。计数值相等的元素按首次出现的顺序排序:
Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]这两个方法是Counter中最常用的方法,其他方法可以参考 python3.10.1官方文档
实战
Leetcode 1002.查找共用字符
给你一个字符串数组words,请你找出所有在words的每个字符串中都出现的共用字符(包括重复字符),并以数组形式返回。你可以按任意顺序返回答案。
输入:words = ["bella", "label", "roller"]
输出:["e", "l", "l"]
输入:words = ["cool", "lock", "cook"]
输出:["c", "o"]看到统计字符,典型的可以用Counter完美解决。这道题是找出字符串列表里面每个元素都包含的字符,首先可以用Counter计算出每个元素每个字符出现的次数,依次取交集最后得出所有元素共同存在的字符,然后利用elements输出共用字符出现的次数
class Solution:
def commonChars(self, words: List[str]) - List[str]:
from collections import Counter
ans = Counter(words[0])
for i in words[1:]:
ans = Counter(i)
return list(ans.elements())提交一下,发现83个测试用例耗时48ms,速度还是不错的
sorted
在处理数据过程中,我们经常会用到排序操作,比如将列表、字典、元组里面的元素正/倒排序。这时候就需要用到sorted(),它可以对任何可迭代对象进行排序,并返回列表
对列表升序操作:
a = sorted([2, 4, 3, 7, 1, 9])
print(a)
# 输出:[1, 2, 3, 4, 7, 9]对元组倒序操作:
sorted((4,1,9,6),reverse=True)
print(a)
# 输出:[9, 6, 4, 1]使用参数:key,根据自定义规则,按字符串长度来排序:
fruits = ['apple', 'watermelon', 'pear', 'banana']
a = sorted(fruits, key = lambda x : len(x))
print(a)
# 输出:['pear', 'apple', 'banana', 'watermelon']all
all() 函数用于判断给定的可迭代参数iterable中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。元素除了是 0、空、None、False外都算True。注意:空元组、空列表返回值为True。
all(['a', 'b', 'c', 'd']) # 列表list,元素都不为空或0
True
all(['a', 'b', '', 'd']) # 列表list,存在一个为空的元素
False
all([0, 1,2, 3]) # 列表list,存在一个为0的元素
False
all(('a', 'b', 'c', 'd')) # 元组tuple,元素都不为空或0
True
all(('a', 'b', '', 'd')) # 元组tuple,存在一个为空的元素
False
all((0, 1, 2, 3)) # 元组tuple,存在一个为0的元素
False
all([]) # 空列表
True
all(()) # 空元组
Trueany函数正好和all函数相反:判断一个tuple或者list是否全为空,0,False。如果全为空,0,False,则返回False;如果不全为空,则返回True。
F-strings
在python3.6.2版本中,PEP 498提出一种新型字符串格式化机制,被称为 “字符串插值” 或者更常见的一种称呼是F-strings,F-strings提供了一种明确且方便的方式将python表达式嵌入到字符串中来进行格式化:
s1='Hello'
s2='World'
print(f'{s1} {s2}!')
# Hello World!在F-strings中我们也可以执行函数:
def power(x):
return x*x
x=4
print(f'{x} * {x} = {power(x)}')
# 4 * 4 = 16而且F-strings的运行速度很快,比传统的%-string和str.format()这两种格式化方法都快得多,书写起来也更加简单。
本文主要讲解了python几种冷门但好用的函数,更多内容以后会陆陆续续更新~
7种检测Python程序运行时间、CPU和内存占用的方法
1. 使用装饰器来衡量函数执行时间
有一个简单方法,那就是定义一个装饰器来测量函数的执行时间,并输出结果:
import time
from functoolsimport wraps
import random
def fn_timer(function):
@wraps(function)
def function_timer(*args, **kwargs):
t0= time.time()
result= function(*args, **kwargs)
t1= time.time()
print("Total time running %s: %s seconds" %
(function.__name__, str(t1- t0))
)
return result
return function_timer
@fn_timer
def random_sort(n):
return sorted([random.random() for i in range(n)])
if __name__== "__main__":
random_sort(2000000)
输出:Total time running random_sort: 0.6598007678985596 seconds
使用方式的话,就是在要监控的函数定义上面加上 @fn_timer 就行了
或者
# 可监控程序运行时间
import time
import random
def clock(func):
def wrapper(*args, **kwargs):
start_time= time.time()
result= func(*args, **kwargs)
end_time= time.time()
print("共耗时: %s秒" % round(end_time- start_time, 5))
return result
return wrapper
@clock
def random_sort(n):
return sorted([random.random() for i in range(n)])
if __name__== "__main__":
random_sort(2000000)
输出结果:共耗时: 0.65634秒
2. 使用timeit模块
另一种方法是使用timeit模块,用来计算平均时间消耗。
执行下面的脚本可以运行该模块。
这里的timing_functions是Python脚本文件名称。
在输出的末尾,可以看到以下结果:4 loops, best of 5: 2.08 sec per loop
这表示测试了4次,平均每次测试重复5次,最好的测试结果是2.08秒。
如果不指定测试或重复次数,默认值为10次测试,每次重复5次。
3. 使用Unix系统中的time命令
然而,装饰器和timeit都是基于Python的。在外部环境测试Python时,unix time实用工具就非常有用。
运行time实用工具:
输出结果为:
Total time running random_sort: 1.3931210041 seconds
real 1.49
user 1.40
sys 0.08
第一行来自预定义的装饰器,其他三行为:
real表示的是执行脚本的总时间
user表示的是执行脚本消耗的CPU时间。
sys表示的是执行内核函数消耗的时间。
注意:根据维基百科的定义,内核是一个计算机程序,用来管理软件的输入输出,并将其翻译成CPU和其他计算机中的电子设备能够执行的数据处理指令。
因此,Real执行时间和User+Sys执行时间的差就是消耗在输入/输出和系统执行其他任务时消耗的时间。
4. 使用cProfile模块
5. 使用line_profiler模块
6. 使用memory_profiler模块
7. 使用guppy包
文章题目:包含python测试函数耗时的词条
本文链接:http://scyanting.com/article/higodg.html