这里写目录标题
一、pytest单元测试框架介绍
针对软件最小单位 函数、方法 进行正确性的检查测试(针对用例进行测试)
干什么用的?
测试发现:从多个文件找到测试用例
测试执行:按照一定顺序和规则去执行,生成结果
测试判断:通过断言判断预期结果和实际结果的差异
测试报告:冲击测试进度、耗时、通过率、生成测试报告
二、单元测试框架和自动化测试框架有什么关系?
(1)自动化测试框架
提高测试效率较低维护成本,是封装的框架,基本不动了,就像回归用例。而且不懂代码也可以用
(2)单元测试框架
只是自动化测试框架组成部分之一
pom设计模式:只是自动化测试框架组成部分之一
数据驱动
关键字驱动
全局配置文件的封装
日志监控
断言
报告邮件
更多…
三、pytest简介
1.成熟框架、灵活、容易上手
2.可以和selenium、requests、applum结合实现web自动化,接口自动化、app自动化
3.可以实现失败用例重试,比如UI定位不准确,某一个元素加载不完全
4、可以和allure生成美观测试报告
5、可以和jenkind持续集成
6、有强大插件,可以实现生成使用的操作
pytest
pytest-html生成htnl自动化测试报告)
pytest-xdist 测试用例分布执行,多cpu多发,同时多个进程跑用例
pytset-ordering 改变测试用例执行顺序,按照我们的顺序去执行
pytest-rerunfailures 用例失败后重新跑
allure-pytest 用于生成美观的测试报告
7、PC使用:pytest下载成功后,需要在setting中对对应项目进行配置,在运行该项目下测试用例的时候需要选择使用对应的python版本
四、使用pytest默认的测试用例的规则和基础应用
1.模块名必须以test_开头或者以_test结尾
2.测试类必须以Test开头,并且不能有init方法
3.测试方法以test开头
五、pytest运行方式
1.主函数
(1)运行所有用例:pytest.main()
test session starts测试开始 test_login.py .执行的 test_login.py文件,后面的.代表通过
如果我有多个用例,我需要每一个都要写一个main方法吗?
不用,单独写一个文件,把main方法移过去,其他用例里面就可以把main方法去除
all.py
import pytest
if __name__ == '__main__':
# 输出调试信息
pytest.main(['-s'])
test_produce.py
class Testproduct:
def test_01_xinyao(selfself):
print('妖媚')
test_login.py
class TestLogin:
def test_01_baili(selfself):
print('大大方方')
运行all.py结果:
============================= test session starts =============================
platform win32 -- Python 3.8.6, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: D:\pythonProject
plugins: allure-pytest-2.9.43, forked-1.3.0, html-3.1.1, metadata-1.11.0, ordering-0.6, rerunfailures-10.1, xdist-2.3.0
collected 2 items
test_login.py 大大方方
.
test_produce.py 妖媚
.
============================== 2 passed in 0.04s ==============================
(2)运行指定(test_login.py)模块用例
pytest.main(['-s', 'test_login.py'])
(2)运行指定函数
pytest.main(['-s', './testcase/test_login.py::test_01_baili2'])
#nodeid:./testcase/test_login.py::test_01_baili2
#::分隔符
2.命令行模式
(1)pytest运行所有
(2)指定模块
pytest -vs test_login.py
(3)指定用例
指定函数
D:\pythonProject>pytest -vs ./testcase/test_login.py::TestLogin
指定方法
if __name__ == '__main__':
# 输出调试信息
pytest.main(['-s', './testcase/test_login.py::TestLogin::test_01_baili'])
3.读取pytest.ini配置文件运行(常用、方便)
[pytest]
#addopts = -vs --alluredir ./temp
addopts = -vs
testpaths = ./dns/interfacetestcaseip
python_files = *
python_classes = *
python_functions = test_*
markers =
smoke:冒烟用例
usermanage:用户管理模块
user:用户管理模块Test
#interfacetestcase/test_03_dataexception.py
pytest.ini:pytest单元测试框架的核心配置文件
想执行用例分支下面的某个功能某块,就可以根据方法命名规则来区分想要执行的模块,对比标记执行顺序方便,不用一个个去标记,下次执行不一样的也不用大量单个更改
(1)位置:项目根目录
(2)编码格式:ANSI,可以使用notepad++修改编码格式
(3)作用:改变pytest的默认行为
(4)运行的规则:主函数和命令行都会去读取这个文件
[pytest]
#命令行的参数,用空格分隔
addopts = -vs
#测试用例路径
testpaths = ./testcase
#测试用例模块名规则
python_files = test*.py
#类名规则
python_classes = Test*
#方法名规则
python_functions = test
运行:
pytest -vs ./testcase
结果却是:
File "d:\python_ths\ths\lib\site-packages\iniconfig\__init__.py", line 82, in _parse
for lineno, line in enumerate(line_iter):
UnicodeDecodeError: 'gbk' codec can't decode byte 0xb9 in position 63: illegal multibyte sequence
这是因为编码格式的问题
把文件copy出来,用notepad++打开——》中文删除-》编码-》转为ANSI编码格式,再次运行就OK
(5)指定分组执行(冒烟,分模块执行,分接口和web)
比如smoke:冒烟用例,分布在各个模块里面
那就在函数上方加一行
执行某个模块一部分用例和另一某块的一部分用例,那就可以用分组
@pytest.mark.smoke
然后再配置文件pytest.ini中加入
markers =
smoke:冒烟用例
usermanage:用户管理模块
第三步在命令行中执行:
D:\pythonProject>pytest -vs -m "smoke"
如果我想同时执行冒烟分组和其他分组怎么办?
- 第一步在配置文件当中将标记的分组写进去
markers =
smoke:冒烟用例
usermanage:用户管理模块
user:用户管理模块
- 第二步将想要分类到该分组的用例进行标记,标记语法为@pytest.mark.user
- 执行语句
pytest -vx -m "smoke or user"
六、参数详解:主函数模式和命令行模式都可以用
-s:表示输出调试信息,包括打印信息 用例名字和结果
class TestLogin:
def test_01_baili(selfself):
print('大大方方')
if __name__ == '__main__':
# 输出调试信息
pytest.main(['-s'])
-v:详细的信息 用例模块 类方法 执行结果
-s:输出调试信息
-vs:两个参数可以一起用
-n:支持多线程或者分布式运行测试用例(减少运行时间)
pytest.main(['-vs', './testcase/test_login.py', "-n=2"])
-x:有一个用例出错,运行停止
–maxfall=2 :出错两个,停止,最大出错用例数
-k “ao”:执行测试用例有ao字符串 pytest -vs ./testcase -k “ao”
–reruns=2:当有失败的用例,会把失败的用例多跑两次
def test_01_baili(selfself):
time.sleep(3)#睡三秒钟
print('大大方方')
命令行:D:\pythonProject>pytest -vs testcase -n 2
如果一个类有多个方法进行多线程,那么它的线程是怎么分配的呢?
七、用例失败后重新跑
程序中加一个断言: assert 1==2
断言:检查条件,不符合就终止程序
pytest.main(['-s', './testcase/test_login.py', '--reruns=2'])
#当有失败的用例,会把失败的用例多跑两次
结果:
==================== 1 failed, 1 passed, 2 rerun in 0.19s =====================
D:\pythonProject>pytest -vs ./testcase/test_login.py --reruns 2
总结:
(1)主函数模式:
(2)运行所有:pytest.main()
(3)制定模块:pytest.main([‘-s’, ‘test_login.py’])
(4)指定目录:pytest.main([‘-vs’, ./目录名]) ./代表当前目录下
(5)通过nodeid指定用例执行:在all.py中main方法里面
通过文件夹的名称/模块的名称/函数名称或者方法
pytest.main([‘-s’, ‘./testcase/test_login.py::TestLogin::test_01_baili’])
pytest.main([‘-s’, ‘./testcase/test_login.py::TestLogin::test_01_baili’])
命令行模式:
pytest
pytest -vs test_login.py
pytest -vs ./目录名代表当前目录下
八、pytest的执行顺序
不按照书写顺序去执行
加标记
@pytest.mark.run(order=3)
mark做记号; 做标记标记用例的执行顺序
class TestLogin:
def test_01_baili1(selfself):
print('baili1')
@pytest.mark.run(order=1)
def test_01_baili2(selfself):
print('baili2')
def test_01_baili3(selfself):
print('baili3')
def test_01_baili4(selfself):
print('baili4')
输出结果:
九、跳过模块中的用例
1.无条件跳过@pytest.mark.skip(reason="用例要调整")
2.条件跳过@pytest.mark.skipif(age<=18,reason='未成年')
十、生成报告
在执行默认配置的当中增加命令行参数
[pytest]
log_cli = true
log_cli_level = INFO
log_cli_format = %(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s
log_cli_date_format=%Y-%m-%d %H:%M:%S
log_format = %(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)4s: %(message)s
log_date_format=%Y-%m-%d %H:%M:%S
[pytest]
addopts = -vs --html ./report/report.html
testpaths = ./testcase
python_files = test*.py
python_classes = Test*
python_functions = test_01_*
markers =
smoke:冒烟用例
usermanage:用户管理模块
user:用户管理模块
生成如下图报告:
十一、快捷键
Ctrl-Alt-左/右 返回上一步操作的界面