pytest快速入门
第一章:
一、pytest单元测试框架
- 什么是单元测试框架
- 软件开发中,针对最小单位(函数、方法)进行正确性检查
- 单元测试框架种类
- java:Junit
- python:unittest、pytest
- 单元测试框架主要做什么
- 测试发现:从多个文件找到我们测试用例
- 测试执行:按照一定的顺序和规则执行,并生成结果
- 测试判断:通过断言判断预期结果和实际结果的差异
- 测试报告:统计测试进度、耗时、通过率,生成测试报告
二、单元测试框架与自动化框架的关系
(1)什么是自动化测试框架
(2)作用
1) 提高效率降低成本
2)减少人工干预,提高准确性
3)让不懂代码的人也能通过这个框架去实现自动化测试
(3)关系
1)单元测试框架只是自动化测试框架中的组成部分
2)unitest与pytest的区别:
三、pytest简介
1.pytest是一个成熟的python单元框架
2.可以和selenium,requests,appium结合,实现web自动化,接口自动化,app自动化
3.pytest可以实现测试用例的跳过和reruns失败测试用例
4.可以和allure生成美观的测试报告
5.可以和jenkins持续集成
6.有很多强大的插件可实现实用操作—》
- pytest-html:生成html格式的自动化测试报告
- pytest-xdist:测试用例分布式执行,多CPU分发
- pytest-ordering:用于改变测试用例的执行顺序
- pytest-rerunfailures:用于失败后的重跑
- allure-pytets:生成美观的测试报告
可以写个txt,使用pip install -r xxx.txt实现一次性安装
四、使用pytest,默认规则
- 模块名必须以test_开头或_test结尾
- 测试类必须以Test开头,并且不能有init方法
- 测试方法必须以test开头
五、pytest测试用例的运行方式
主函数模式:
(1)执行所有:``` # 在主函数中使用pytest.main() if __name__ == '__main__': pytest.main() ```
(2)指定模块运行:
``` if __name__ == '__main__': pytest.main(['-vs','test_id.py']) ```
(3)指定目录运行
``` if __name__ == '__main__': # 测试interface_testcase 目录下的全部用例 pytest.main(['-vs','interface_testcase']) if __name__ == '__main__': # 测试interface_testcase 目录下的test_interface01.py 中的用例 pytest.main(['-vs','interface_testcase/test_interface01.py']) ```
(4)通过node_id指定用例运行:nodeid由模块名,分隔符,类名,方法名等组成
pytest.main(['-vs','interface_testcase/test_interface01.py::类名::方法名'])
命令行模式
1. 运行所有:pytest 2. 指定模块:pytest -vs test_goods.py 3. 指定目录:pytest -vs ./testcase 4. 通过node_id指定用例运行:pytest -vs ./interface_testcase/test_interface01.py::类名::方法名
参数详解:
if __name__ == '__main__': pytest.main(['参数'])
-s:表示输出调试信息,输出print信息 -v:显示更加详细的信息 -vs:两个参数可以同时使用 -n:支持多线程或者分布式运行 -if __name__ == '__main__': # 有两个线程来执行testcase 目录下的测试用例 pytest.main(['-vs','testcase','-n 2']) --reruns=num:失败用例重跑,将这个模块多执行num次,最后返回结果 -x:只要有一个用例失败,测试就会停止 --maxfail=2:如果有两个测试用例失败,测试停止 -k:根据测试用例的部分字符串指定测试用例 '-k "case"' --hetml ./报告文件夹/xxx.html 生成html格式报告
- 读取pytest.ini配置文件运行:pytest.ini是pytest单元测试框架的核心配置文件
1. 位置:一般放在项目的根目录 2. 编码:必须是ANSI,可以使用notepad++修改编码格式 3. 作用:改变pytest默认的行为 4. 运行规则:不管是主函数的模式运行还是命令行模式运行,都会读取这个文件
- 重要:可以改变pytest的默认规则,比如执行不再以test开头的类,方法等
[pytets]addopts=-vs #命令行参数,用空格分隔 testpaths= ./xxx #测试用例的路径 python_files=test_*.py #模块命名的规则 python_classes=Test* #类名的规则 python_functions=test #方法名的规则
- 重要:可以改变pytest的默认规则,比如执行不再以test开头的类,方法等
六、 pytest 执行顺序
unittest:根据ASCII大小执行
pytest:默认按照用例先后顺序执行
可以通过@pytest.mark.run(order=)来指定执行顺序
七、如何分组执行
在python.ini中加入
markers =
smoke:冒烟用例
usermanage:用户管理模块
...
在分组的模块上加上@pytest.mark.xxx
需要同时执行时使用:pytest -vs -m "smoke or xxx"
八、 跳过用例执行
(1)无条件跳过(使用装饰器)
@pytest.mark.skip(reason="跳过原因")
(2)有条件跳过
@pytest.mark.skipif(age>=18,reason='已成年') # 条件成立时跳过
第二章
一、pytest框架实现前后置(固件,夹具)的处理,常用三种
setup/teardwon (全是小写)
- setup_class方法: 在每个类执行前的初始化操作,在所有用例之前只执行一次
- 一般用来创建日志对象、数据库链接、接口的请求对象等
- setup方法:每个用例前都执行一次
- teardown方法:每个用例后执行一次
- teardown_class方法:每个类执行后的扫尾工作,只会执行一次,
- 一般用来销毁日志对象,销毁数据库连接,销毁接口请求对象等
- setup_class方法: 在每个类执行前的初始化操作,在所有用例之前只执行一次
fixture装饰器,实现部分用例的前后置
setup不可部分执行
语法规则:在方法上面声明:@pytest.fixture(scope="" ,params="",autouse="", ids="", name="")
scope:被装饰器标记的方法的作用域,可以作用于function(默认)(每个方法前后都执行一次),class(只执行一次),module(一次),package/session
params:参数化(支持列表[],元组(),字典列表[{},{}],字典元组({},{}))
autouse:Ture、False(默认),是否自动执行
ids:当使用参数化时,给每一个值设置一个变量名
name:给所标记的方法取一个别名
@pytest.fixture(scope="function") def my_fix(): print() yield # 用于分割前后置 print() class Testxxx: def test_01(self,my_fix): 会调用,加了autouse就不用写了 def test_02(self): 不会调用,如果加了autouse,所有方法都会调用
# 加参数的fixture @pytest.fixture(scope="function",params=['x','y','z']) def my_fix(request): return request.param class Testxxx: def test_01(self,my_fix): # 会调用 print('\n^^^^'+str(myfix)) # 如果是列表的话,会在调用fix的地方依次调用列表中的元素,会将这个用例执行三次 def test_02(self): # 不会调用
在参数化时要注意,yield与return不可同时使用(不能在一个方法里同时实现前后置和参数化),封装成两个方法即可。return和yield都表示返回的意思,但return后不能再有代码,yield可以有。
在使用name给fix方法取别名之后,可以用别名来传参,但是原名就不能用了
通过conftest.py和@pytest.fixture()结合使用,实现全局的前置应用
- 比如项目的全局登录,模块的全局处理
- conftest.py文件是单独存放的一个夹具配置文件,名称不能更改
- 可以在不同的py文件中使用同一个fixture函数
- 原则上该文件需要和我们要运行的用例放在同一层,且不需要任何import导入操作(但实际上不是同一层也能用)
- 在调用fix方法时,作为参数可以传入多个不同的fix方法,谁放在最前面谁就是最早到最晚走的
二. 断言
assert
三. pytest结合allure-pytest生成allure测试报告
- 下载(github)、解压、配置path(环境变量)
- 验证:allure --version
- 生成json格式的临时报告:在ini文件里 addopts加--alluredir ./temp(临时目录报告路径)
- 生成allure报告:在main方法里加:
os.system('allure generate ./temp -o ./report --clean(清除原有的报告)')
四、 @pytest.mark.parametrize()基本用法
@pytest.mark.parametrize(args_name,args_b=value)
* args_name:参数名,
* args_b=value:参数值,支持列表,元组,字典列表,字典元组。有多少个值,就会执行多少次用例
@pytest.mark.parametrize('args',['xx','xxx','xx']) def test_01(self,args): # 参数名作为方法参数传入 print(args) # 和unitest中ddt里面的@unpack解包一样 @pytest.mark.parametrize('name,age',[['百里','16'],['时影','22']]) def test_01(self,name,age): # 参数名作为方法参数传入 print(name) print('*:'+age)
第三章
一、结合yaml文件实现接口自动化
作用:
- 用于全局的配置文件-- ini、yaml
- 用于写测试用例
yaml简介:
- yaml是一种数据格式,支持注释,换行,多行字符串,裸字符串(整形,字符串)
yaml语法规则
- 区分大小写
- 使用缩进表示层级,不能使用tab键,只能使用空格
- 缩进没有数量,只要前面时对齐的就行
- ‘#’注释
数据组成(可以多行写也可以一行写)
- Map对象:键值对-- 键:(空格)值
- 多行写:
xxx: name:zxy identity:millionaire
- 一行写
xxx:{name:zxy, identity:millionaire}
- 多行写:
- 数组前面加:‘-’ (对齐的横线是一组数组)
- 多行写:
- xxx: -name:zxy -identity:millionaire - xxx: -name:zhou -identity:millionaire
- 一行写
xxx:[{name:zxy}, {identity:millionaire}]
- 多行写:
- Map对象:键值对-- 键:(空格)值
使用方法
创建一个yamlutil的类,在里面通过init方法把yaml文件传入到类中
写一个方法read_yaml读取yaml文件
在其中使用yaml.load()对yaml反序列化--将yaml转换成dict格式
class YamlUtil: def __init__(self,yaml_file): self.yaml_file=yaml_file def read_yaml(path): with open(self.yam_file,encoding='utf-8') as f: value = yaml.load(f,Loader=yaml.FullLoader) return value #然后在主方法中就能使用反序列化yaml方法: if __name__== '__main__': YamlUtil('test_api.yaml').read_yaml()
yaml自动化实战
- 断言的封装
- allure报告定制
- 关键字驱动和数据驱动结合实现接口自动化测试
- python的反射
- jenkins的持续集成和allure报告集成,并且根据自动化报告的错误率发送电子邮件