admin 管理员组文章数量: 887021
Pytest
一、pytest封装测试类
文件命名:以test_开头
测试类命名:以Test_开头
测试用例命名:以test_开头
二、前置/后置方法
前置方法:
setup
放在类外只对类外方法有效,每条测试方法执行前都执行一次,在setup_function后执行。放在类内只对类内方法有效,每条测试用例执行前都执行一次,在setup_method后执行。
setup_function
放在类外对类外测试方法有效,每条测试方法执行前都执行一次,在setup前执行。放在类内无效。
setup_method
放在类内对类内测试方法生效,每条测试方法执行前都执行一次,在setup前执行。放在类外无效。
setup_class
放在类内对类内测试方法生效,类内所有测试方法执行前执行一次,在setup/setup_function/setup_method前执行。放在类外无效。
setup_model
放类中无效,放类外且类外有函数用例或类内有函数用例时才生效,整个.py模块开始前和结束后各调用一次。
后置方法:
teardown
teardown_function
teardown_method
teardown_class
teardown_model
三、测试用例执行顺序控制
import pytest-ordering
在测试用例前添加装饰@pytest.mark.run(order=XX)
import pytestclass TestOrder:@pytest.mark.run(order=3)def test_case1(self):print('test_case1')@pytest.mark.run(order=1)def test_case2(self):print('test_case2')@pytest.mark.run(order=2)def test_case3(self):print('test_case3')if __name__=="__main__":pytest.main(["-s","test_practice.py"])
四、测试用例跳过
1.直接跳过
测试方法前直接加:@pytest.mark.skip(“说明”)
2.条件跳过
设置条件:
例如: condition1 = '冒烟'
测试类前加条件,对该文件所有测试类生效。
测试类中加条件,仅对该测试类生效。
条件使用:
@pytest.mark.skipif(condition1 == '冒烟', reason='smoketest')
def test_case1(self):
print('test_case1')
说明:当condition1 == '冒烟'判定成功,test_case1跳过不执行。
3.样例代码
import pytestcondition1='class外部'
class TestSkip1:condition2='class内部'@pytest.mark.skip('直接跳过test_case1')def test_case1(self):print('test_case1')@pytest.mark.skipif(condition1 == 'class外部', reason='外部条件class1内部生效')def test_case2(self):print('test_case2')@pytest.mark.skipif(condition2 == 'class内部', reason='class1内部条件class1内部生效')def test_case3(self):print('test_case3')def test_case4(self):print('test_case4')
#内部标签整个模块内生效
class TestSkip2:@pytest.mark.skipif(condition1 == 'class外部', reason='外部条件class2内部生效')def test_case5(self):print('test_case5')
@pytest.mark.skipif(condition1 == 'class外部', reason='外部条件外部方法生效')
def test_case6(self):print('test_case6')
#内部标签外部不生效
# @pytest.mark.skipif(condition2 == 'class内部', reason='class1内部条件外部无法使用')
# def test_case7(self):
# print('test_case7')
if __name__=="__main__":pytest.main(["-rs","test_practice.py"])
五、测试用例标签:
1.在pytest.ini文件中声明标签
[pytest] # 固定的section名
markers= # 固定的option名称
标签名1: 标签名的说明内容。
标签名2
标签名N
2.给测试用例加标签
方式一:@pytest.mark.已注册标签名
一个用例可以添加多个标签
方式二:pytestmark = [pytest.mark.已注册标签名]
可以加多个pytestmark = [pytest.mark.已注册标签名1,pytest.mark.已注册标签名2]
在类里面使用声明类内所有用例都会标记。
在模块(文件)里面标记,该文件所有用例都会打上该该标记。
3.使用标签过滤执行
pytest -m "Label" 路径或者文件
4.样例代码
import pytest@pytest.mark.classLabel('classLabel')
class TestLabel1:@pytest.mark.Label1('label1')def test_case1(self):print('test_case1')@pytest.mark.Label2('label2')def test_case2(self):print('test_case2')@pytest.mark.Label3('label3')def test_case3(self):print('test_case3')@pytest.mark.Label4('label4')
def test_case4():print('test_case4')if __name__=="__main__":# pytest.main(["-m", "Label1", "-s", "test_practice.py"])# pytest.main(["-m", "not Label1", "-s", "test_practice.py"])# pytest.main(["-m", "Label1 or Label3", "-s", "test_practice.py"])# pytest.main(["-m", "classLabel and Label3", "-s", "test_practice.py"])pytest.main(["-m", "classLabel and not Label3", "-s", "test_practice.py"])
六、传参
1.方式一:@pytest.fixture()
fixture是在测试函数运行前后,由pytest执行的外壳函数,执行顺序在测试用例代码之前,类似于unittest中的setup,在其中定义作为finalizer(终结器)使用的函数才会在测试用例执行后执行,类似于unittest中的teardown。
# test_fixture.pyimport pytest@pytest.fixture()
def fixtureFunc():return 'fixtureFunc'def test_fixture(fixtureFunc):print('我调用了{}'.format(fixtureFunc))if __name__=='__main__':pytest.main(['-v', 'test_fixture.py'])
参数说明:
name: 可以使用name参数给装饰器起别名,用别名传参,起了别名就不能用函数名传参。
scope :作用域参数,session(会话级,每次会话只需要运行一次),module(模块),class(测试类),function(测试用例)
autouse--自动执行:默认False,如果改为True,则不需要调用,在对应的作用域会自动执行。
params --实现参数化(数据驱动)
import pytestdata = [("username1", "password1"), ("username2", "password2")]@pytest.fixture(scope="function", params=data)
def get_data(request):print(request.param)return request.paramdef test_login(get_data):print("账号:%s" % get_data[0], "密码:%s" % get_data[1])if __name__ == '__main__':pytest.main(["-s", "test_practice.py"])# *****************输出信息**************
('username1', 'password1')
账号:username1 密码:password1
.('username2', 'password2')
账号:username2 密码:password2
2.方式二:@pytest.mark.parametrize()
@pytest.mark.parametrize(('param1','param2'),(['param1value1','param2value1'],['param1value2','param2value2']))
@pytest.mark.parametrize('num',test_case01) #test_case01只能是普通方法,不能加fixture标签,该方法有返回值(一般直接处理成list类型)
说明:装饰器定义了几个参数,测试方法就要传入几个参数,每组测试数据数量和参数的个数要相等,执行测试方法时每一组测试数据自动执行一次该测试方法,类似循环,第一次传入第一组测试数据['name1','password1'],第二次传入['name2','password2']。
import pytest@pytest.mark.parametrize(('name','password'),(['name1','password1'],['name2','password2']))
def test_case1(name,password):print(name)print(password)# for date in name:# print(date)
if __name__=="__main__":pytest.main(["-vs","test_practice.py"])
==============================控制台输出==============================
test_practice.py::test_case1[name1-password1] name1
password1
PASSED
test_practice.py::test_case1[name2-password2] name2
password2
PASSED
七、常用钩子函数:
1.在html测试报告中添加测试人信息
2.在html测试报告中添加测试执行时间
3.在测试报告中添加错误截图
样例代码如下:
import pytest
import time
from py.xml import html
import pytest
from selenium import webdriver# 在html测试报告中添加测试人信息
@pytest.mark.optionalhook
def pytest_html_results_summary(prefix, summary, postfix):prefix.extend([html.p("测试人: zg")])#在html测试报告中添加测试执行时间
@pytest.mark.optionalhook
def pytest_html_results_table_row(report, cells):cells.insert(3, html.td(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), class_='col-time'))cells.pop()# 设置一个browser固件
@pytest.fixture(scope='session', autouse=True)
def browser():global driverif driver is None:driver = webdriver.Chrome()return driver#定义截屏方法
def _capture_screenshot():return driver.get_screenshot_as_base64()#定义添加错误图片的钩子函数
@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):"""当测试失败的时候,自动截图,展示到html报告中:param item:"""pytest_html = item.config.pluginmanager.getplugin('html')outcome = yieldreport = outcome.get_result()extra = getattr(report, 'extra', [])if report.when == 'call' or report.when == "setup":xfail = hasattr(report, 'wasxfail')if (report.skipped and xfail) or (report.failed and not xfail):file_name = report.nodeid.replace("::", "_") + ".png"screen_img = _capture_screenshot()if file_name:html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:600px;height:300px;" ' \'onclick="window.open(this.src)" align="right"/></div>' % screen_imgextra.append(pytest_html.extras.html(html))report.extra = extra
八、测试报告
1.HTML报告
(1)安装类库 pytest-html
(2)conftest中定制报告内容,即添加钩子函数到conftest.py
(3)生成默认html报告
执行测试脚本命令中添加参数“--html=测试报告.html”。
例如:
terminal中执行:pytest --html=测试报告.html。
main函数中执行:pytest.main(['test_login.py','--html=测试报告.html'])
2.allure测试报告
(1)环境准备
1)依赖java,需安装JDK
2)allure安装包
下载最新版本的allure-commandline-2.*.*.zip ,解压到任意不含中文的路径下,并配置其中bin文件夹的环境变量到path。
下载链接:/
3)安装类库allure-pytest
(2)生成allure测试报告
1)pytest 测试脚本.py --alluredir= ./tmp/my_allure_results
在指定路径下生成测试报告所需文件及数据。
2)allure serve ./tmp/my_allure_results
生成即时观看的allure测试报告(未生成具体的测试报告文件)
3)allure generate ./tmp/my_allure_results
创建生成allure的html格式的报告
九、日志
1.pytest自带日志模块
(1)import logging
(2)记录器Logger
1)创建Logger
logger = logging.getLogger(name=None)
创建具有层次结构的记录器是,使用 '.' 点号分割,如'a'、'a.b'等,a是b的父记录器,b继承a的配置。未指定name时,返回Logger根实例,名称是root。
2)设置Logger
<1>设置日志级别(记录日志时不会记录比设置级别低的日志)
Logger.setLevel(level = logging.DEBUG)
包含如下级别:
CRITICAL
ERROR
WARNING
INFO
DEBUG
NOTSET # 作为 logger 的默认值。
<2>添加Handler
logger.addHandler(filehandler)
<3>添加Filter
logger.addFilter()
<4>记录日志
logger.debug("logger debug log")
logger.info("logger info log")
logger.warning("logger warning log")
logger.error("logger error log")
logger.critical("logger critical log")
(3)处理器Handler
处理器,将(记录器产生的)日志记录发送至合适的目的地,可以是控制台、文件。
1)创建Handler
<1>流处理器StreamHandler
console =logging.StreamHandler(stream=None)
stream是流的意思,默认值为系统输出流:sys.stderr,可以输出内容到Terminal。也输出内容到自定义文件。
import loggingf=open('test1.log','a') # 打开一个文件
logger = logging.getLogger('test') #实例化一个记录器
logger.setLevel(level = logging.DEBUG) #设置记录器的错误级别
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 设置一个输出格式
console = logging.StreamHandler(f) #实例化一个流处理器
console.setFormatter(formatter) #设置流处理器格式
logger.addHandler(console) #将流处理器添加到记录器
# 在记录器中记录日志
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")
<2>文件处理器FileHandler
filehandler = logging.FileHandler(filename, mode='a', encoding=None)
将对应记录器的日志输出到filename对应文件中,同时也会输出到终端。FileHandler()会自动打开filename文件,打开方式有mode决定,默认值为'a'。
2)设置Handler
<1>设置日志级别
filehandler.setLevel()
<2>设置格式
filehandler.setFormatter()
<3>添加Filter
logger.addFilter()
(4)日志格式Formatter
格式化器,指明了最终输出中日志记录的布局。
1)创建Formatter
formatter=logging.Formatter()
常用参数如下:
%(levelno)s 打印日志级别的数值
%(levelname)s 打印日志级别名称
%(pathname)s 打印当前执行程序的路径
%(filename)s 打印当前执行程序名称
%(funcName)s 打印日志的当前函数
%(lineno)d 打印日志的当前行号
%(asctime)s 打印日志的时间
%(thread)d 打印线程id
%(threadName)s 打印线程名称
%(process)d 打印进程ID
%(message)s 打印日志信息
例如:formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
2.logging.basicConfig()函数
使用basicConfig()函数直接进行直接在测试脚本中配置日志
(1)参数说明
filename:指定日志输出文件,及其位置
filemode:执行日志输出到文件的方式,默认为'a',追加写入
format:指定输出日志的格式
datefmt:指定输出日志中的日期格式
level:指定输出那个级别及其以上级别日志
(2)样例代码
import logginglogging.basicConfig(level=logging.INFO,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',datefmt='[%Y-%m_%d %H:%M:%S]',filename='./my.log',filemode='a')logging.critical('logging critical message.')
logging.error('logging error message')
logging.warning('logging warning message')
logging.info('logging info message')
logging.debug('logging debug message')
3.日志模块公共配置文件
(1)import logging.config
(2)创建*.conf文件
文件后缀固定,名称自定。例如:logger.conf
1)创建Logger
在[loggers]下通过关键字keys配置需要创建的Logger,创建多个时用英文逗号隔开
[loggers]
keys=root,file
2)为每个Logger配置相关属性
[logger_root]是说明为哪个Logger配置属性,例如[logger_root],就是为root记录器配置属性,即步骤一中keys后面配置的值。关键字level设置日志级别,关键字handlers为记录器添加处理器。
[logger_root]
level=DEBUG
handlers=hand01
3)创建handler
在[handlers]下通过关键字keys配置需要创建的handler,创建多个时用英文逗号隔开
[handlers]
keys=hand01,hand01
4)为每个handler配置相关属性
[handler_hand01]是说明为哪个handler配置属性,例如[handler_hand01],就是为hand01处理器配置属性,即步骤三中keys后面配置的值。
[handler_hand01] #[handler_hand01]是说明为哪个handler配置属性,例如[handler_hand01],就是为hand01处理器配置属性,即步骤三中keys后面配置的值。
class=StreamHandler #关键字class说明处理器的类型
level=WARNING # 关键字level设置日志级别,记录日志级别大于等于处理设置日志级别才能输出,小于不处理
formatter=form01 #关键字formatter设置为该处理器添加日志输出格式
args=(sys.stderr,) 该处理器的参数列表,StreamHandler流处理器(sys.stderr,),FileHandler文件处理器args=('python.log', 'a')
5)创建formatter
在[formatters]下通过关键字keys配置需要创建的formatter,创建多个时用英文逗号隔开
[formatters]
keys=form01,form02
6)为每个formatter配置相关属性
[formatter_form01]是说明为哪个formatter配置属性,例如[formatter_form01],就是为form01格式化器配置属性,即步骤三中keys后面配置的值。
[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
datefmt=%a, %d %b %Y %H:%M:%S
7)样例代码
###############################################
[loggers]
keys=root
[logger_root]
level=DEBUG
handlers=hand01
###############################################
[handlers]
keys=hand01
[handler_hand01]
class=StreamHandler
level=WARNING
formatter=form01
args=(sys.stderr,)
[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form02
args=('python.log', 'w')
###############################################
[formatters]
keys=form01,form02
[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
datefmt=%a, %d %b %Y %H:%M:%S
[formatter_form02]
format=%(name)-12s: %(levelname)-8s %(message)s
datefmt=%a, %d %b %Y %H:%M:%S
(3)测试脚本中引用配置文件
1)导入类库
import logging
import logging.config
2)测试脚本中添加该配置文件
logging.config.fileConfig('logger.conf')
3)实例化配置文件中某个记录器
root_logger = logging.getLogger('root')
4)记录器中添加日志,运行测试脚本
5)样例代码
import logging
import logging.configlogging.config.fileConfig('logger.conf') # 测试脚本中添加该配置文件
root_logger = logging.getLogger('root') # 实例化配置文件中root记录器
root_logger.debug('test root logger...') # 记录器中添加日志
十、FAQ
1.脚本的并发
安装类库pytest -xdist
执行脚本添加参数"-n=4"
2.配置文件pytest.ini
pytest.ini 可以改变 pytest 的默认行为,不管是主函数模式运行,命令行模式运行,都会去先读取这个全局配置文件。如pytest.ini有该参数值,在执行的时候,先读取配置文件中的参数,如没有,则取其他地方的(主函数/命令行中)。
(1)文件首行写[pytest]
(2)定义标签,指定测试内容
第五章
(3)配置测试执行参数
脚本运行参数设置,多个参数用英文空格隔开。在这里设置后,通过命令行或者mian方法运行脚本时不用在添加参数。例:addopts =-v -s
获取帮助 :pytest --help
-s:在Termail中执行测试用例py文件,默认不执行print语句,想要执行需加上-s参数
-rs:输出跳过测试方法原因,同时也会输出print语句
-v:更详细的运行信息
-m:通过指定标签来过滤运行哪些用例
-k :通过指定关键来过滤运行哪些用例
--lf:只执行上次失败的用例
--tb:
--tb=no:不展示用例失败的错误详情。
--tb=line:展示用例失败的代码具体行数
-x:遇到错误停止
–maxfail=num:错误用例达到次数停止
--duration=N:表示把最耗时间的用例展示出来,N表示最慢的N个
(4)指定执行测试用例范围
配置多个参数取交集
1)testpaths:指定路径
testpaths=./test_script/authority ./test_script/user
通过路径来挑选测试方法,执行配置路径下所有测试脚本中所有方法。可以配置多个路径,用英文空格隔开。未配置的路径,即使配置对应的脚本或者类或者方法也不执行
2)python_files:指定文件
python_files=完整测试脚本名
python_files=测试脚本名前缀*
配置文件会执行文件所有测试用例,配置多个文件用英文空格隔开。用通配符时,仅支持后面加通配符,前后都加执行时会卡在挑选测试方法步骤执行不下去。
3)python_classes:指定测试类
python_classes=完整测试类名
python_classes=测试类名前缀*
配置测试类会执行类中所有测试方法,配置多个测试类用英文空格隔开。不是类方法的配置了对应文件,未配置对应测试方法也执行。
4)python_functions:指定测试用例
python_functions=完整方法名
python_functions=测试方法名前缀*
配置多个用英文空格隔开。用通配符时,仅支持后面加通配符,前后都加执行时会卡在挑选测试方法步骤执行不下去。
5)样例
[pytest]
markers=Labelname1:labelvalue1Labelname2:labelvalue3...addopts=-v -rs -s
testpaths=./test_script
python_files=test_pytest_workflow1.py test_practice.py
python_classes=TestLabel2 TestClass1
3.配置文件contest.py
(1)contest.py说明
conftest.py 文件名称是固定的,不能改动。
conftest.py不需导入,pytest执行自动调用。
一个项目中可以有多个conftest.py。一个conftest.py只对同一路径下的其它文件以及其子文件生效。
(2)使用场景
1)设置全局变量
2)测试数据处理
大批量的脚本需要使用相同的测试数据,可以放在conftest.py中进行数据处理。
3)添加钩子函数
使用pytest-html生成测试报告添加钩子函数,定义报告样式
本文标签: Pytest
版权声明:本文标题:Pytest 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1688320674h205823.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论