fixture的优势
Pytest的fixture相对于传统的xUnit的setup/teardown函数做了显著的改进:
命名方式灵活,不局限于 setup 和teardown 这几个命名 conftest.py 配置里可以实现数据共享,不需要 import 就能自动找到fixture scope="module" 可以实现多个.py 跨文件共享前置 scope="session" 以实现多个.py 跨文件使用一个 session 来完成多个用例 ?fixture参数列表
@pytest.fixture(scope="function",?params=None,?autouse=False,?ids=None,?name=None) def?test(): ????print("fixture初始化的参数列表")
参数列表
scope: fixture的作用域,有四个级别参数 "function" (默认), "class", "module" or "session". params: 一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它 autouse: ?如果为True,则为所有测试激活fixture func 可以看到它。 如果为False(默认值)则显式需要参考来激活fixture ids: 每个字符串id的列表,每个字符串对应于params 这样他们就是测试ID的一部分。 如果没有提供ID它们将从params自动生成 name: ? 默认:装饰器的名称,同一模块的fixture相互调用建议写个不同的name ?fixture的使用方式
将fixture名称作为测试用例函数的输入参数 测试用例加上装饰器:@pytest.mark.usefixtures(fixture_name) fixture设置autouse=True ?方式一:作为函数入参的fixture
测试函数可以通过接受一个已经命名的fixture对象来使用他们。对于每个参数名,如果fixture已经声明定义,会自动创建一个实例并传入该测试函数。fixture函数通过装饰器标志@pytest.fixture来注册。
#?test_1.py import?pytest? @pytest.fixture def?login(): ????print("输入账号,密码先登录") def?test_1(login): ????print("用例?1:登录之后其它动作?111") def?test_2():??#?不传?login ????print("用例?2:不需要登录,操作?222")
测试结果
collected?2?items?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? test_example.py?输入账号,密码先登录 用例?1:登录之后其它动作?111 .用例?2:不需要登录,操作?222 .
?
方式二:usefixtures
@pytest.fixture def?login1(): ????print("输入账号,密码先登录") @pytest.fixture def?login2(): ????print("please输入账号,密码先登录") @pytest.mark.usefixtures("login1",?"login2") def?test_s1(): ????print("用例?11:登录之后其它动作?111")
测试结果
collected?1?item??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? test_example.py?输入账号,密码先登录 please输入账号,密码先登录 用例?11:登录之后其它动作?111 .
?
usefixtures与传fixture区别
fixture可以获取返回值,而usefixture无法获取返回值,这个是装饰器fixture与用例直接传fixture参数的区别,所以这里就建议大家就用传参的方式 ?
方式三:fixture设置autouse=True
import?pytest @pytest.fixture(autouse=True) def?login3(): ????print("====auto===") def?test_s3(): ??print("测试用例")
测试结果
test_example.py? ====auto=== 测试用例 .
?
conftest.py: 共享fixture函数
实现测试用例的过程中,当你发现需要使用来自多个文件的fixture函数的时候,可以将这些fixture函数放到conftest.py中。 ?
conftest.py配置需要注意以下点:
conftest.py配置脚本名称是固定的,不能改名称 conftest.py与运行的用例要在同一个pakage下,并且有__init__.py文件 不需要import导入 conftest.py,pytest用例会自动查找共享测试数据
如果要使用数据文件中的测试数据,最好的方法是将这些数据加载到fixture函数中以供测试方法注入使用。这利用到了pytest的自动缓存机制。
另一个好方法是在tests文件夹中添加数据文件。 还有社区插件可用于帮助处理这方面的测试,例如:pytest-datadir和pytest-datafiles。 ?
作用域
一个工程下可以建多个conftest.py的文件,一般在工程根目录下的conftest.py文件起到全局作用,在不同子目录下也可以放conftest.py文件,作用只能在该层目录及以下目录实现 conftest在不同的层级间的作用域不一样 conftest是不能跨模块调用的一般情况下,只会在项目根目录下,建立一个conftest.py,提供全局作用域 ?
fixture scope的范围参数
之前使用@pytest.fixture(scope='module')来定义框架,scope的参数有以下几种
funciton 每一个函数或方法都会调用 class 每一个类调用一次,一个类可以有多个方法 module 每一个.py文件调用一次,该文件内又有多个function和class session 每个session只运行一次,在自动化测试时,登录步骤可以使用该session范围:session > module > class > function ?
fixture自动使用autouse=True
当用例很多的时候,每次都传这个参数,会很麻烦。fixture里面有个参数autouse,默认是False没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了
autouse设置为True,自动调用fixture功能
autouse的fixture遵循以下规则:
autouse fixture遵守scope的定义,如果autouse fixture的scope为"session",那么这个fixture无论定义在哪儿都只会运行一次,定义为"class"则表示在每个class中只会运行一次。
如果在module中定义了autouse,那么该module中的所有测试用例都会自动使用该fixture
如果在conftest.py中定义了autouse,那么该目录下的所有测试用例都会自动使用该fixture
最后,请谨慎使用该功能,如果你在插件中定义了一个autouse的fixture,那么所有使用了该插件的测试用例都会自动调用该fixture。这种方式在某些情况下是有用的,比如用ini文件配置fixture,这种全局的fixture应该快速有效的确定它应该完成哪些工作,避免代价高昂的导入和计算操作。 ?
fixture调用结束/执行清理代码
pytest支持在fixture退出作用域的时候执行相关的清理/结束代码。使用yield而不是return关键字的时候,yield后面的语句将会在fixture退出作用域的时候被调用来清理测试用例,相当于unittest里的teardown作用 ?
yield
@pytest.fixture(scope="function")? def?smtp_connection():? ????smtp_connection?=?smtplib.SMTP("smtp.gmail测试数据",?587,?timeout=5)? ????yield?smtp_connection? ????print("teardown?smtp")? ????smtp_connection.close() ?? #?无论测试是否发生了异常,print及smtp.close()语句将在function测试函数完成之后被执行
除了yield可以实现teardown,在request-context对象中注册addfinalizer方法也可以实现终结函数。 ?
addfinalizer
@pytest.fixture(scope="module")? def?smtp_connection(request):? ????smtp_connection?=?smtplib.SMTP("smtp.gmail测试数据",?587,?timeout=5)? ????def?fin():? ????????print("teardown?smtp_connection")? ????????smtp_connection.close()? ????request.addfinalizer(fin)? ????return?smtp_connection
yield和addfinalizer在测试结束之后的调用是基本类似的,addfinalizer主要有两点不同于yield:
可以注册多个完成函数
无论fixture的代码是否存在异常,addfinalizer注册的函数都会被调用,这样即使出现了异常,也可以正确的关闭那些在fixture中创建的资源
所以推荐大家都是用addfinalizer这种方式 ?
查看更多关于Pytest(3)fixture的使用的详细内容...