pytest框架之fixture详细使用
本人之前写了一套基于unnitest框架的UI自动化框架,但是发现了pytest框架之后觉得unnitest太low,现在重头开始学pytest框架,一边学习一边记录,和大家分享,话不多说,那就先从pytest框架的精髓fixture说起吧!
简介:
fixture区别于unnitest的传统单元测试(setup/teardown)有显著改进:
1.有独立的命名,并通过声明它们从测试函数、模块、类或整个项目中的使用来激活。
2.按模块化的方式实现,每个fixture都可以互相调用。
3.fixture的范围从简单的单元测试到复杂的功能测试,可以对fixture配置参数,或者跨函数function,类class,模块module或整个测试session范围。
(很重要!!!)(很重要!!!)(很重要!!!)
谨记:当我们使用pytest框架写case的时候,一定要拿它的命令规范去case,这样框架才能识别到哪些case需要执行,哪些不需要执行。
用例设计原则
文件名以test_*.py文件和*_test.py
以test_开头的函数
以Test开头的类
以test_开头的方法
fixture可以当做参数传入
定义fixture跟定义普通函数差不多,唯一区别就是在函数上加个装饰器@pytest.fixture(),fixture命名不要以test开头,跟用例区分开。fixture是有返回值得,没有返回值默认为None。用例调用fixture的返回值,直接就是把fixture的函数名称当做变量名称。
ex:
import pytest @pytest.fixture()
def test1():
a = 'leo'
return a def test2(test1):
assert test1 == 'leo' if __name__ == '__main__':
pytest.main('-q test_fixture.py') 输出:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 1 item test_fixture.py . [100%] ========================== 1 passed in 0.02 seconds ===========================
Process finished with exit code 0
使用多个fixture
如果用例需要用到多个fixture的返回数据,fixture也可以返回一个元祖,list或字典,然后从里面取出对应数据。
ex:
import pytest @pytest.fixture()
def test1():
a = 'leo'
b = ''
print('传出a,b')
return (a, b) def test2(test1):
u = test1[0]
p = test1[1]
assert u == 'leo'
assert p == ''
print('元祖形式正确') if __name__ == '__main__':
pytest.main('-q test_fixture.py') 输出结果:
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 1 item test_fixture.py 传出a,b
.元祖形式正确
[100%] ========================== 1 passed in 0.02 seconds ===========================
Process finished with exit code 0
当然也可以分成多个fixture,然后在用例中传多个fixture参数
import pytest @pytest.fixture()
def test1():
a = 'leo'
print('\n传出a')
return a @pytest.fixture()
def test2():
b = ''
print('传出b')
return b def test3(test1, test2):
u = test1
p = test2
assert u == 'leo'
assert p == ''
print('传入多个fixture参数正确') if __name__ == '__main__':
pytest.main('-q test_fixture.py') 输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 1 item test_fixture.py
传出a
传出b
.传入多个fixture参数正确
fixture互相调用
import pytest @pytest.fixture()
def test1():
a = 'leo'
print('\n传出a')
return a def test2(test1):
assert test1 == 'leo'
print('fixture传参成功') if __name__ == '__main__':
pytest.main('-q test_fixture.py') 输出结果:
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 1 item test_fixture.py
传出a
.fixture传参成功
[100%] ========================== 1 passed in 0.03 seconds ===========================
Process finished with exit code 0
介绍完了fixture的使用方式,现在介绍一下fixture的作用范围(scope)
fixture的作用范围
fixture里面有个scope参数可以控制fixture的作用范围:session>module>class>function
-function:每一个函数或方法都会调用
-class:每一个类调用一次,一个类中可以有多个方法
-module:每一个.py文件调用一次,该文件内又有多个function和class
-session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module
fixture源码详解
fixture(scope='function',params=None,autouse=False,ids=None,name=None):
scope:有四个级别参数"function"(默认),"class","module","session"
params:一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它。
autouse:如果True,则为所有测试激活fixture func可以看到它。如果为False则显示需要参考来激活fixture
ids:每个字符串id的列表,每个字符串对应于params这样他们就是测试ID的一部分。如果没有提供ID它们将从params自动生成
name:fixture的名称。这默认为装饰函数的名称。如果fixture在定义它的统一模块中使用,夹具的功能名称将被请求夹具的功能arg遮蔽,解决这个问题的一种方法时将装饰函数命令"fixture_<fixturename>"然后使用"@pytest.fixture(name='<fixturename>')"。
具体阐述一下scope四个参数的范围
scope="function"
@pytest.fixture()如果不写参数,参数就是scope="function",它的作用范围是每个测试用例来之前运行一次,销毁代码在测试用例之后运行。
import pytest @pytest.fixture()
def test1():
a = 'leo'
print('\n传出a')
return a @pytest.fixture(scope='function')
def test2():
b = '男'
print('\n传出b')
return b def test3(test1):
name = 'leo'
print('找到name')
assert test1 == name def test4(test2):
sex = '男'
print('找到sex')
assert test2 == sex if __name__ == '__main__':
pytest.main('-q test_fixture.py') 输出结果: platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 2 items test_fixture.py
传出a
.找到name 传出b
.找到sex
[100%] ========================== 2 passed in 0.04 seconds ===========================
放在类中实现结果也是一样的
import pytest @pytest.fixture()
def test1():
a = 'leo'
print('\n传出a')
return a @pytest.fixture(scope='function')
def test2():
b = '男'
print('\n传出b')
return b class TestCase:
def test3(self, test1):
name = 'leo'
print('找到name')
assert test1 == name def test4(self, test2):
sex = '男'
print('找到sex')
assert test2 == sex if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py']) 输出结果: platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 2 items test_fixture.py
传出a
.找到name 传出b
.找到sex
[100%] ========================== 2 passed in 0.03 seconds ===========================
Process finished with exit code 0
scope="class"
fixture为class级别的时候,如果一个class里面有多个用例,都调用了次fixture,那么此fixture只在此class里所有用例开始前执行一次。
import pytest @pytest.fixture(scope='class')
def test1():
b = '男'
print('传出了%s, 且只在class里所有用例开始前执行一次!!!' % b)
return b class TestCase:
def test3(self, test1):
name = '男'
print('找到name')
assert test1 == name def test4(self, test1):
sex = '男'
print('找到sex')
assert test1 == sex if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py']) 输出结果:
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 2 items test_fixture.py 传出了男, 且只在class里所有用例开始前执行一次!!!
.找到name
.找到sex
[100%] ========================== 2 passed in 0.05 seconds ===========================
Process finished with exit code 0
scope="module"
fixture为module时,在当前.py脚本里面所有用例开始前只执行一次。
import pytest
##test_fixture.py @pytest.fixture(scope='module')
def test1():
b = '男'
print('传出了%s, 且在当前py文件下执行一次!!!' % b)
return b def test3(test1):
name = '男'
print('找到name')
assert test1 == name class TestCase: def test4(self, test1):
sex = '男'
print('找到sex')
assert test1 == sex if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py']) 输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 2 items test_fixture.py 传出了男, 且在当前py文件下执行一次!!!
.找到sex
.找到name
[100%] ========================== 2 passed in 0.03 seconds ===========================
Process finished with exit code 0
scope="session"
fixture为session级别是可以跨.py模块调用的,也就是当我们有多个.py文件的用例的时候,如果多个用例只需调用一次fixture,那就可以设置为scope="session",并且写到conftest.py文件里。
conftest.py文件名称时固定的,pytest会自动识别该文件。放到项目的根目录下就可以全局调用了,如果放到某个package下,那就在改package内有效。
文件目录为
import pytest
# conftest.py @pytest.fixture(scope='session')
def test1():
sex = '男'
print('获取到%s' % sex)
return sex
import pytest
# test_fixture.py def test3(test1):
name = '男'
print('找到name')
assert test1 == name if __name__ == '__main__':
pytest.main(['-s', 'test_fixture.py'])
import pytest
# test_fixture1.py class TestCase: def test4(self, test1):
sex = '男'
print('找到sex')
assert test1 == sex if __name__ == '__main__':
pytest.main(['-s', 'test_fixture1.py'])
如果需要同时执行两个py文件,可以在cmd中在文件py文件所在目录下执行命令:pytest -s test_fixture.py test_fixture1.py
执行结果为:
================================================= test session starts =================================================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:
collected 2 items test_fixture.py 获取到男
找到name
.
test_fixture1.py 找到sex
. ============================================== 2 passed in 0.05 seconds ===============================================
调用fixture的三种方法
1.函数或类里面方法直接传fixture的函数参数名称
import pytest
# test_fixture1.py @pytest.fixture()
def test1():
print('\n开始执行function') def test_a(test1):
print('---用例a执行---') class TestCase: def test_b(self, test1):
print('---用例b执行') 输出结果:
test_fixture1.py
开始执行function
.---用例a执行--- 开始执行function
.---用例b执行
[100%] ========================== 2 passed in 0.05 seconds ===========================
Process finished with exit code 0
2.使用装饰器@pytest.mark.usefixtures()修饰需要运行的用例
import pytest
# test_fixture1.py @pytest.fixture()
def test1():
print('\n开始执行function') @pytest.mark.usefixtures('test1')
def test_a():
print('---用例a执行---') @pytest.mark.usefixtures('test1')
class TestCase: def test_b(self):
print('---用例b执行---') def test_c(self):
print('---用例c执行---') if __name__ == '__main__':
pytest.main(['-s', 'test_fixture1.py']) 输出结果:
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 3 items test_fixture1.py
开始执行function
.---用例a执行--- 开始执行function
.---用例b执行--- 开始执行function
.---用例c执行---
[100%] ========================== 3 passed in 0.06 seconds ===========================
Process finished with exit code 0
叠加usefixtures
如果一个方法或者一个class用例想要同时调用多个fixture,可以使用@pytest.mark.usefixture()进行叠加。注意叠加顺序,先执行的放底层,后执行的放上层。
import pytest
# test_fixture1.py @pytest.fixture()
def test1():
print('\n开始执行function1') @pytest.fixture()
def test2():
print('\n开始执行function2') @pytest.mark.usefixtures('test1')
@pytest.mark.usefixtures('test2')
def test_a():
print('---用例a执行---') @pytest.mark.usefixtures('test2')
@pytest.mark.usefixtures('test1')
class TestCase: def test_b(self):
print('---用例b执行---') def test_c(self):
print('---用例c执行---') if __name__ == '__main__':
pytest.main(['-s', 'test_fixture1.py']) 输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 3 items test_fixture1.py
开始执行function2 开始执行function1
.---用例a执行--- 开始执行function1 开始执行function2
.---用例b执行--- 开始执行function1 开始执行function2
.---用例c执行---
[100%] ========================== 3 passed in 0.03 seconds ===========================
Process finished with exit code 0
usefixtures与传fixture区别
如果fixture有返回值,那么usefixture就无法获取到返回值,这个是装饰器usefixture与用例直接传fixture参数的区别。
当fixture需要用到return出来的参数时,只能讲参数名称直接当参数传入,不需要用到return出来的参数时,两种方式都可以。
fixture自动使用autouse=True
当用例很多的时候,每次都传这个参数,会很麻烦。fixture里面有个参数autouse,默认是False没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了
autouse设置为True,自动调用fixture功能
import pytest
# test_fixture1.py @pytest.fixture(scope='module', autouse=True)
def test1():
print('\n开始执行module') @pytest.fixture(scope='class', autouse=True)
def test2():
print('\n开始执行class') @pytest.fixture(scope='function', autouse=True)
def test3():
print('\n开始执行function') def test_a():
print('---用例a执行---') def test_d():
print('---用例d执行---') class TestCase: def test_b(self):
print('---用例b执行---') def test_c(self):
print('---用例c执行---') if __name__ == '__main__':
pytest.main(['-s', 'test_fixture1.py']) 输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\exercise, inifile:collected 4 items test_fixture1.py
开始执行module 开始执行class 开始执行function
.---用例a执行--- 开始执行class 开始执行function
.---用例d执行--- 开始执行class 开始执行function
.---用例b执行--- 开始执行function
.---用例c执行---
[100%]
conftest.py的作用范围
一个工程下可以建多个conftest.py的文件,一般在工程根目录下设置的conftest文件起到全局作用。在不同子目录下也可以放conftest.py的文件,作用范围只能在改层级以及以下目录生效。
项目实例:
目录结构:
1.conftest在不同的层级间的作用域不一样
# conftest层级展示/conftest.py import pytest @pytest.fixture(scope='session', autouse=True)
def login():
print('----准备登录----') # conftest层级展示/sougou_login/conftest
import pytest @pytest.fixture(scope='session', autouse=True)
def bai_du():
print('-----登录百度页面-----') # conftest层级展示/sougou_login/login_website
import pytest class TestCase:
def test_login(self):
print('hhh,成功登录百度') if __name__ == '__main__':
pytest.main(['-s', 'login_website.py']) 输出结果: ============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\conftest层级演示\sougou_login, inifile:collected 1 item login_website.py ----准备登录----
-----登录百度页面-----
.hhh,成功登录百度
[100%] ========================== 1 passed in 0.03 seconds ===========================
Process finished with exit code 0
2.conftest是不能跨模块调用的(这里没有使用模块调用)
# conftest层级演示/log/contfest.py
import pytest @pytest.fixture(scope='function', autouse=True)
def log_web():
print('打印页面日志成功') # conftest层级演示/log/log_website.py
import pytest def test_web():
print('hhh,成功一次打印日志') def test_web1():
print('hhh,成功两次打印日志') if __name__ == '__main__':
pytest.main(['-s', 'log_website.py']) 输出结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-4.0.2, py-1.7.0, pluggy-0.8.0
rootdir: C:\Program Files\PycharmProjects\conftest层级演示\log, inifile:
collected 2 items log_website.py ----准备登录----
打印页面日志成功
hhh,成功一次打印日志
.打印页面日志成功
hhh,成功两次打印日志
. ========================== 2 passed in 0.02 seconds ===========================
今天先介绍到这,过几天继续更新,希望和大家多多学习!转载请说明出处,尊重劳动成果!!!
pytest框架之fixture详细使用的更多相关文章
- pytest框架之fixture前置和后置
一.conftest.py 定义公共的fixture,多个测试类中都可以调用 pytest提供了conftest.py文件,可以将fixture定义在此文件中 运行测试用例时,不需要去导入这个文件,会 ...
- pytest框架 里 fixture 参数化的方法
- 【pytest系列】- fixture测试夹具详解
如果想从头学起pytest,可以去看看这个系列的文章! https://www.cnblogs.com/miki-peng/category/1960108.html fixture的优势 pyt ...
- 『德不孤』Pytest框架 — 11、Pytest中Fixture装饰器(一)
目录 1.Fixture装饰器的用途 2.Fixture参数说明 3.Fixture装饰器简单应用 4.yield执行后置函数 1.Fixture装饰器的用途 做测试前后的初始化设置,如测试数据准备, ...
- Appium 并发多进程基于 Pytest框架
前言: 之前通过重写unittest的初始化方法加入设备参数进行并发,实现了基于unittest的appium多设备并发,但是考虑到unittest的框架实在过于简陋,也不方便后期的Jenkins的持 ...
- pytest 框架自动化Selenium 之yield 使用
环境 python 3.7 由于3.0-3.5以下部分pytest可能有部分兼容问题安装建议2.7-2.9,3.5-最新 pip install pytest专属 pytest框架包 pip inst ...
- 手把手教你搭建Pytest+Allure2.X环境详细教程,生成让你一见钟情的测试报告(非常详细,非常实用)
简介 宏哥之前在做接口自动化的时候,用的测试报告是HTMLTestRunner,虽说自定义模板后能满足基本诉求,但是仍显得不够档次,高端,大气,遂想用其他优秀的report框架替换之.一次偶然的机会, ...
- pytest框架使用教程
Pytest框架 一.简介 pytest:基于unittest之上的单元测试框架 有什么特点? 自动发现测试模块和测试方法 断言更加方便,assert + 表达式,例如 assert 1 == 1 灵 ...
- pytest框架的安装与使用
pytest框架的安装与使用 一,pytest了解 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高. ...
随机推荐
- AutoLayout(自动布局)
1. iOS两种自适应布局方式:(修正说明:) -AutoLayout(自动布局) + SizeClasses(尺寸类别) -Autoresizing (自动调整尺寸/弹簧式调整尺寸) 前者 Auto ...
- git&sourcetree安装及在IntelliIJ下拉取项目基础使用
be careful: 1)git版本与Sourcetree版本最好一致 ,不能git为2.5,sourcetree为1.8 2)先安装git再安装Sourcetree 3)拥有git和sourcet ...
- 自定义web服务器(四)
关于HTTP协议的具体内容,前面章节已经有所讲解,相信读者已有所了解,在此不在累述,本章节讲解自定义web服务器. 一,.net提供自定义Web服务器的类 以下只是写主要的类 1.HTTPListe ...
- Git添加Gitee远程仓库
1.使用IDEA初始化仓库,并提交代码 2.使用 git remote add origin https://gitee.com/你的码云用户名/XXXX //添加远程仓库 3.使用 git pull ...
- 51nod 1103 N的倍数
1103 N的倍数 一个长度为N的数组A,从A中选出若干个数,使得这些数的和是N的倍数. 例如:N = 8,数组A包括:2 5 6 3 18 7 11 19,可以选2 6,因为2 + 6 = 8, ...
- 用字典给Model赋值
用字典给Model赋值 此篇教程讲述通过runtime扩展NSObject,可以直接用字典给Model赋值,这是相当有用的技术呢. 源码: NSObject+Properties.h 与 NSObje ...
- getpass模块
# -*- coding: utf-8 -*- #python 27 #xiaodeng #getpass模块 import getpass ''' >>> help(getpass ...
- [SoapUI] 在Test Step 下加Script Assertion,用 messageExchange 获取当前步骤的response content
//Get response content of the current request def response = messageExchange.getResponseContent() // ...
- Springcloud中的region和zone的使用
一.背景 用户量比较大或者用户地理位置分布范围很广的项目,一般都会有多个机房.这个时候如果上线springCloud服务的话,我们希望一个机房内的服务优先调用同一个机房内的服务 ,当同一个机房的服务不 ...
- scrapy-splash抓取动态数据例子十六
一.介绍 本例子用scrapy-splash爬取梅花网(http://www.meihua.info/a/list/today)的资讯信息,输入给定关键字抓取微信资讯信息. 给定关键字:数字:融合:电 ...