L1
pytest测试用例编写规则
模块命名
以test_开头或_test结尾
类命名
以Test开头,类名驼峰命名
方法命名
以test_开头
* 注意测试类中不能添加__init__方法
pytest测试用例结构
测试用例名称,测试步骤,断言
def test_method():
#测试步骤
assert 1==1
pytest测试用例断言
什么是断言
断言是一个在程序中的一阶逻辑(如:一个结果为真或假的逻辑判断式),目的为了表示与验证软件开发着的预期结果,–当程序执行到断言的位置时,对应的断言应该为真,若断言不为真时,程序会中止执行,并给出错误信息
断言表达式
assert Expression1
assert Expression1,Expression2
Expression1总为布尔值,Expression2为是断言失败时,抛出的断言错误信息字符
断言示例
def test_001():
assert 2==2,'结果相等'
def test_a():
assert False
def test_c():
assert 'abc' in 'abcd'
pytest测试框架结构
setup和teardown框架结构
pytest setup和pytest teardown介绍
1、setup_module和teardown_module;全局模块级
2、setup_class和teardown_class ;类级,只在类中前后运行一次
3、setup_function和teardown_function;函数级,在类外
4、setup_method和teardown_method;方法级,类中的每个方法执行前后
5、setup和teardown 在类中,运行在调用方法的前后(重点)
# 模块级 在类外
def setup_module(self):
print('模块级前置')
def teardown_module(self):
print('模块级后置')
class TestSetUpModule:
def test_aa01(self):
print('test_aa01')
def test_aa02(self):
print('test_aa02')
# 方法级,在类中
class TestSetUp_method:
def setup_method(self):
print('方法级前置')
def teardown_method(self):
print('方法级后置')
def test_aa03(self):
print('test_aa03')
def test_aa04(self):
print('test_aa04')
# 函数级在类外
def setup_function(self):
print('函数级前置')
def teardown_function(self):
print('函数级后置')
def test_aa05():
print('test_aa05')
def test_aa06():
print('test_aa06')
# 方法级,在类内
class TestSetUp_class:
def setup_class(self):
print('类级别前置')
def teardown_class(self):
print('类级别后置')
def test_aa07(self):
print('test_aa07')
def test_aa08(self):
print('test_aa08')
# 每个方法前后,类内
class TestSetUp:
def setup(self):
print('调用方法前置')
def teardown(self):
print('调用方法后置')
def test_aa09(self):
print('test_aa09')
def test_aa10(self):
print('test_aa10')
*调用先后顺序:模块级(setup_module/teardown_module)在类外>函数级(setup_function/teardown_function)类外>类级(setup_class/teardown_function)类中>方法级(set_method/teardown_method)每个方法前后执行
L2
pytest参数化用例
参数化:
1、通过参数的方式传递数据,从而实现数据和脚本分离
2、并且可以实现用例的重复生成与执行
参数化应用场景
1、测试登录场景
测试登录成功,登录失败
参数化实现方案
pytest参数化实现方法
装饰器:@pytest.mark.parametrize
@pytest.mark.parametrize("username,password",[['admin','123456']])
def test_login(username,password):
print(f'姓名为:{username},密码为:{password}')
参数化测试函数使用
单参数
单参数:可以将数据放在列表中
search_list=['appium','selenium','hook']
@pytest.mark.parametrize('key_word',['appium','selenium','sale'])
def test_search(key_word):
assert key_word in search_list
多参数
将数据放在列表嵌套元组中
@pytest.mark.parametrize('a,b,c',[(1,1,2),(2,2,5)])
def test_search(a,b,c):
assert a+b==c
将数据放在列表嵌套列表中
@pytest.mark.parametrize('a,b,c',[[1,1,2],[2,2,5]])
def test_search(a,b,c):
assert a+b==c
参数化-用例重命名-添加ids参数
通过ids参数,将别名放在列表中
@pytest.mark.parametrize('a,b,c',[[1,1,2],[2,2,5]],ids=('one','two'))
def test_search(a,b,c):
assert a+b==c
参数化:用例重命名-添加ids参数(中文)
笛卡尔积
将每个参数穷举组合
@pytest.mark.parametrize('a',['appium','selenium','doc','hah'])
@pytest.mark.parametrize('b',[1,2,3])
def test_001(a,b):
print(f'笛卡尔积{a}--{b}')
pytest标记测试用例
mark: 跳过(skip)及预期失败(xfail)
这是pytest的内置标签,可以处理一些特殊的测试用例,不能成功的测试用例
1、跳过标记:@pytest.mark.skip(始终跳过该测试用例)
2、有条件跳过:@pytest.mark.skipif(遇到特定情况跳过该测试用例)
3、预期失败:@pytest.mark.xfail(标记的用例错误,产生一个“期望失败”输出)
skip使用场景
- 调试时不想运行这个用例
- 标记无法在某些平台上运行的测试功能
- 在某些版本中执行,其他版本中跳过
- 比如:当前的外部资源不可用时跳过
如果测试数据是从数据库中取到的,
连接数据库的功能如果结果返回失败就跳过,因为执行也都报错 - 解决1: 添加装饰器
@pytest.mark.skip
@pytest.mark.skipif - 解决2:代码中添加跳过代码
@pytest.skip(reason)
import pytest
class TestSkip:
@pytest.mark.skip
def test_skip(self):
print('跳过用例')
a=2
@pytest.mark.skipif(a>1,reason='测试')
def test_skipif(self):
print('跳过用例')
xfail使用场景
- 与skip类似,预期结果为fail,标记用例为xfail
- 用法:添加装饰器@pytest.mark.xfail
class Testxfail:
@pytest.mark.xfail
def test_xfail(self):
assert 1==2
pytest运行用例
运行多条用例
运行某个/多个用例包
1、运行包下的所有用例 pytest
运行某个/多个用例模块
1、运行单个 pytest 文件名
运行某个/多个 用例类
1、pytest 文件名::类名
运行某个/多个用例方法
1、pytest 文件名::类名::方法名
pytest测试用例调度与运行
命令行参数-使用缓存状态
- –lf(–last-failed) 只重新运行故障
- –ff(–failed-first) 先运行故障然后再运行其他的测试用例
pytest命令行常用参数
命令行参数-常用命令行参数
- -x 用例一旦失败(fail/error),就立刻停止执行
- -m 被@pytest.mark.标记的用例 pytest -m ‘smoke1 and smoke2’
- –maxfail=num 指定最大失败次数,达到最大失败次数以后停止运行
- -k 执行包含关键字的测试用例
- -v 打印详细日志
- -s 打印输出日志 一般-vs一块儿使用
- -collect-only 测试平台,pytest自动导入功能
python执行pytest
python-代码执行pytest-main函数
if __name__ == '__main__':
# 1、运行当前目录下所有符合规则的用例,包括子目录(test_*.py 和 *_test.py)
pytest.main()
# 2、运行test_mark1.py::test_dkej模块中的某一条用例
pytest.main(['./testcase/test_loginnew/test_user.py','-vs'])
pytest.main(['test_mark1.py::test_dkej','-vs'])
# 3、运行某个 标签
pytest.main(['test_mark1.py','-vs','-m','dkej'])
运行方式
`python test_*.py `
pytest异常处理
L3
#数据驱动
什么是数据驱动
数据驱动就是数据的改变从而驱动自动化测试的执行,最终引起测试结果的改变,简单来说,就是参数化的应用,数据量小的测试用例可以使用代码的参数化来实现数据驱动,数据量大的情况下建议大家使用一张结构化的文件(yaml,json)来对数据进行存储,然后在测试用例中读取这些数据
应用
- APP、Web、接口自动化测试
- 测试步骤的数据驱动
- 测试数据的数据驱动
- 配置的数据驱动
pytest结合数据驱动-yaml
yaml文件介绍
对象:键值对的集合,用冒号“:”表示
数组:一组按次序排列的值
纯量:单个的,不可再分的值
- 字符串
- 布尔值
- 整数
- 浮点数
- Null
- 时间
- 日期
eg
# 编程语言
languages:
- PHP
- Java
- Python
book:
Python入门: # 书籍名称
price: 55.5
author: Lily
available: True
repertory: 20
date: 2018-02-17
Java入门:
price: 60
author: Lily
available: False
repertory: Null
date: 2018-05-11
yaml文件使用
读写yaml文件
- 安装 pip3 install pyyaml
- 读 ymal.safe_load(f)
- 写 yam.safe_dump(data,f)
读
with open('test.yaml',encoding='utf-8') as f:
yaml.safe_load(f)
写
with open('test.yaml',mode='a',encoding='utf-8') as f:
yaml.safe_dump('bb',f)
# a=yaml.safe_load(f)
pytest结合数据驱动-execl
pytest结合数据驱动-csv
pytest结合数据驱动-json
pytest测试用例生命周期管理(一)
fixture特点及优势
1、命令灵活:可以不起setup,teardown两个名字
2、数据共享:在conftest.py 配置里写方法可以实现数据共享,不需要import导入,可以跨文件导入
3、scope的层次及神奇的yield相当于各种setup和teardown
4、实现参数化
fixture在自动化中的应用-基本用法
场景:测试用例执行时,有的用例需要登录才能执行,有些用例不需要登录,setup和teardown无法慢煮,fixture可以,默认scope为function
步骤:
1、在conftest写好登录函数加上装饰器@pytest.fixture()
2、在要使用的测试方法中传入(登录函数名称),就会前置先登录
3、测试方法不传入的就不会调用登录
conftest.py
-----
@pytest.fixture()
@pytest.mark.parametrize("username,password,code,uuid",readdata()['Userdata'])
def get_login_token(username,password,code,uuid):
json={"username":username,"password":password, "code":code,"uuid":uuid}
res = requestClient.sendrequest(url="http://localhost:8013/auth/login", json=json, method='post')
print(res.json())
def test(get_login_token):
pass
pytest测试用例生命周期管理(二)
fixture用法,fixture在自动化中的应用-作用域
取值 范围 说明
funtion 函数级 每一个函数和方法都会调用
class 类级别 每一个测试类只运行一次
module 模块级 每一个.py 文件调用一次
package 包级 每一个 python 包只调用一次(暂不支持)
session 会话级 每次会话只需要运行一次,会话内所有方法及类,模块都共享这个方法
pytest测试用例生命周期管理(三)
Fixture在自动化中的应用-yield关键字
场景:测试方法前的依赖解决了,测试方法后销毁清除数据的要如何进行
解决:在fixture函数中加入yield关键字,yield是调用第一次返回结果,第二次执行它下面的语句
步骤:
@pytest.fixture()
def get_login_token(username,password):
print('登录成功')
yield
print('退出登录')
pytest测试用例生命周期管理(四)
fixture在自动化中的应用-数据共享
场景:你与其他测试⼯程师合作⼀起开发时,公共的模块要在不同⽂件中,要在⼤家都访问到的地⽅。
解决:使用conftest.py这个文件进行共享,可放在不同位置起着不同的范围共享
执行: 1、 系统执⾏到参数 login 时先从本模块中查找是否有这个名字的变量什么的,
2 、之后在 conftest.py 中找是否有。
步骤:将登陆模块带@pytest.fixture 写在 conftest.py
pytest测试用例生命周期管理-自动生效
fixture在自动化中的应用-自动应用
在函数上@pytest.fixture(@autouse=Ture)
pytestfixture实现参数化
fixture在自动化中的应用-参数化
场景:
测试离不开数据,为了数据灵活,一般数据都是通过参数传的
解决:
fixture通过固定参数request传递
步骤:
在fixture中增加@pytest.fixture(params=[{‘admin’:‘123456’},{‘wyl’:‘12346’}])
在方法参数写request,方法体里面使用request.param接收参数
@pytest.fixture(params=[{'admin':'123456'},{'wyl':'12346'}])
def login(request):
return request.param
#
def test_001(login):
for i ,v in login.items():
print(i,v)
Fixture的用法总结
L4
pytest配置文件【进阶】
pytest.ini是什么
1、pytest.ini 是pytest的配置文件
2、可以修改pytest的默认行为
3、不能使用任何中文符号,包含汉字、空格、引号、冒号等
pytest.ini
1、修改用例的命名规则
;执行check开头和test开头的所有的文件,后面一定要加*
python_files = check_* test_*
;执行所有以Test和Check的类
python_classes = Test* Check*
;执行所有以test_和check_开头的方法
python_functions = test_* check_*
2、配置日志格式,比代码配置更方便
3、添加标签,防止运行过程报警错误
4、指定执行目录
;设置执行的路径
testpaths = 文件路径
;忽略某些文件夹/目录
norecursedirs = 文件夹/目录
5、添加默认参数
addopts = -v -s --alluredir=./results
pytest插件【进阶】
pytest插件分类
1、内置插件:代码内部的_pytest目录加载
2、外部插件:pip install 安装的插件
pip install 安装的插件
pip install pytest-ordering 控制用例的执行顺序
pip install pytest-rerunfailures 失败重跑
pip install pytest-assume 多种校验
pip install pytest-repeat 重复执行用例
pip install pytest-html 测试结果生成html报告插件
3、本地插件
pytest测试用例执行顺序自定义pytest-ordering【进阶】
场景:
对于集成测试,经常会有上下文依赖关系的测试用例
用例默认是自上而下执行
解决:
可以通过setup、teardown和fixture来解决,也可以使用对应的插件
1、安装 pip install pytest-ordering
2、用法@pytest.mark.run(order=1)
import pytest
class TestOrder:
def test_01(self):
print('test')
@pytest.mark.run(order=1)
def test_02(self):
print('最开始运行')
pytest测试用例并行运行和分布式运行【进阶】
场景1:
测试用例1000条,一个用例执行1分钟,一个测试人员执行需要1000分钟
通常我们会用人力成本换取时间成本,加几个人一起执行,时间就会缩短
如果10人一起执行只需要100分钟,这就是一种分布式场景
场景2:
假设有个报名系统,对报名总数统计,数据同时进行修改操作的时候有可能出现问题
需要模拟这个场景,需要多用户并发请求数据
用例较多时,效果明显
解决:
使用分布式并发执行测试用例,分布式插件:pytest-xdist
安装:pip install pytest-xdist
运行:
1、pytest -s -n auto
参数 -n auto 自动检测到系统的cpu数量,此时所有的cpu都来执行测试用例
2、pytest -s -n 2,指定执行cpu数
分布式执行测试用例原则
1、用例之间是独立的,不要有依赖关系
2、用例执行没有顺序,随机顺序都能正常秩序
3、每个用例都能重复运行,运行结果不回影响其他用例