参考学习官网文档:https://docs.pytest.org/en/latest/getting-started.html
一、pytest简介
1. 前言:测试框架与测试工具
- 测试框架、测试工具这两个概念经常容易搞混了,测试框架是诸如 Unittest、Pytest、TestNG 这类,而测试工具指的则是 Selenium、Appium、Jmeter 这类。
- 测试框架的作用是,帮助管理测试用例、执行测试用例、参数化、断言、生成测试报告等基础性工作,让我们将精力用在测试用例的编写上。好的测试框架应该具有很高的扩展性,支持二次开发,并能够支持多种类型的自动化测试。
- 测试工具的作用是为了完成某一类型的测试,比如 Selenium 用于对 WEB UI 进行自动化测试,Appium 用来对 APP 进行自动化测试,Jmeter 可以用来进行 API 自动化测试和性能测试。另外,Java 语言中 OkHttp 库,Python 语言中的 requests 库,这些 HTTP 的 client 也可以看做是一种 API 测试工具。
2. 单元测试框架
- 1)什么是单元测试框架?
单元测试是指软件开发中,针对软件的最小单位(函数、方法)进行正确性的检查测试,Java:junit、testing
Python:unittest、pytest- 2)单元测试框架主要做什么?
① 测试发现:从多个文件里面去找我们得测试用例
② 测试执行:按照一定的顺序和规则去执行,并生成结果
③ 测试判断:通过断言判断预期结果和实际结果的差异
④ 测试报告:统计测试进度、耗时、通过率、生成测试报告
3. pytest简介
- Pytest 是 Python 的一种易用、高效和灵活的单元测试框架,可以支持单元测试和功能测试
- pytest可以和selenium,requests,appium结合实现web自动化、接口自动化、app自动化
- pytest可以实现测试用例的跳过以及reruns(失败用例重试)
- pytest可以和allure生成非常美观的测试报告
- pytest可以和jenkins持续集成
- pytest有很多非常强大的插件,并且这些插件能够实现很多实用的操作
① pytest-xdist:测试用例分布式执行,多cpu分发
② pytest-ordering:用于改变测试用例的执行顺序
③ pytest-rerunfailures:用例失败后重跑
④ pytest-html:生成html格式的自动化测试报告
⑤ allure-pytest:用于生成美观测试报告
二、安装pytest
pytest需要:Python 3.7+ 或 PyPy3
- 在命令行中运行以下命令
pip install -U pytest
其他插件安装方法也是一样pip安装
-
检查是否安装成功pytest
三、pytest使用规则
- 模块名必须以
test_
开头或test_
结尾 - 测试类必须以
Test
开头,且不能有init
方法 - 测试方法必须以
test
开头
使用规则
四、测试用例执行
pytest 用例的执行主要有以下三种方式:
- 通过命令模式执行
- 通过主函数执行
- 通过读取 pytest.ini 配置文件执行
4.1 通过命令模式执行
测试文件test_demo.py:Pytest 使用 Python 的 assert
进行条件判断,简单的测试函数如:
def test_product_case001():
print("模拟测试模块1的功能")
assert 1 + 1 == 3
def test_product_case002():
print("模拟测试模块2的功能")
assert 1 == 1
1)执行所有用例
pytest
命令执行当前目录下所有的测试用例,所以要想执行项目中所有的用例,只需要将执行目录切换到根目录即可:
可以加上-v参数查看详情pytest -v
2)指定执行
执行指定目录:4.2 通过主函数执行
1)主函数运行
test_demo.py添加主函数:
import pytest
class Testdemo:
def test_case_passed(self):
print("模拟执行成功场景的case")
assert (1, 2, 3) == (1, 2, 3)
def test_case_failed():
print("模拟执行失败场景的case")
assert 3 == 1 + 1
if __name__ == '__main__':
pytest.main(["-v"]) # 执行测试用例,-v参数打印详细信息
然后直接运行:从终端的打印可以看到,用例文件中的用例方法 test_case_failed
以及测试类中的测试方法 test_case_passed
都被执行了。
2)批量执行
只需要在对应的用例文件中调用主函数,就可以自动执行文件中的所有用例。
但是在实际的使用中,一般会将用例分类写在不同目录下的不同用例文件里,且执行时要批量去执行所有的用例,所以往往会将主函数写在一个与用例文件夹平级的 py 文件中,pytest 内部设有对应的机制,会自动扫描全局,执行所有的用例文件。
运行主函数文件main.py
,输出结果可以看到所有用例均被执行了:
3)指定执行
pytest.main()可以加上命令参数运行,如下
4.3 通过 pytest.ini 配置文件执行
在项目中,通常通过配置全局的配置文件来执行测试用例的。其余两种执行方式在编写和调试用例时比较方便。对于配置文件,有以下几点要求:
- 配置文件的名字必须为 pytest.ini
- 配置文件一般放置在项目的根目录
- 配置文件必须时 ANSI 编码
- 配置了pytest.ini文件后,不管是主函数模式运行用例,还是命令行模式运行用例,都会去读取pytest.ini配置文件中的内容。
- CMD命令行中执行pytest -h命令,可以查看pytest.ini的设置选项。
pytest.ini 是 pytest 框架的核心配置文件,它可以改变 pytest 的默认行为,不管是通过主函数还是命令模式去执行用例,都会先去读取配置文件。
五、执行参数
我们在执行用例时,可以通过添加相关的参数实现不同的执行效果,提升测试效率。
1)-s:用于输出调试信息,包括打印输出的信息
# 通过main函数执行
pytest.main(["-s", "./product_cases/test_product.py"])
# 通过命令模式执行
pytest -s ./product_cases/test_product.py
2)-v:显示更详细的信息
# 通过main函数执行
pytest.main(["-v", "./product_cases/test_product.py"])
# 通过命令模式执行
pytest -v ./product_cases/test_product.py
3)-vs:将 -v 和 -s 参数效果结合,推荐使用
-vs
4)-n:支持多线程或者分布式运行测试用例
n是进程数,也就是cpu个数,最大值为当前机器cpu个数,也可以设置为auto,自动识别cpu个数。
# 通过main函数执行
# 开两个线程去执行用户操作目录下所有的用例
pytest.main(["-vs", "./product_cases", "-n=2"])
# 通过命令模式执行
pytest -vs ./product_cases -n 2
为了方便看出测试效果,给test_product.py文件中的每个测试用例都增加sleep(2)
import pytest,time
def test_product_case001():
time.sleep(2)
print("模拟测试模块1的功能")
assert 1 + 1 == 2
def test_product_case002():
time.sleep(2)
print("模拟测试模块2的功能")
assert 1 == 1
正常执行结果:用时4.05s5)--reruns:失败用例重跑
# 通过main函数执行
# 如果用例执行失败,该用例再执行2次
pytest.main(["-vs", "./product_cases", "--reruns=2"])
# 通过命令模式执行
pytest -vs ./product_cases --reruns 2
修改test_product.py文件
def test_product_case001():
print("模拟测试模块1的功能")
assert 1 + 1 == 3
def test_product_case002():
print("模拟测试模块2的功能")
assert 1 == 1
6)-x:只要有一个用例失败,就停止执行
# 通过main函数执行
pytest.main(["-vs", "./product_cases", "-x"])
# 通过命令模式执行
pytest -vs ./product_cases -x
test_product_case001
失败,停止执行,test_product_case002
未执行
7)--maxfail:失败的用例数达到规定值时停止测试
# 失败的用例数达到2个时停止测试
# 通过main函数执行
pytest.main(["-vs", "./product_cases", "--maxfail=2"])
# 通过命令模式执行
pytest -vs ./product_cases --maxfail 2
8)-k:关键字过滤执行
-k会匹配文件名、类名、方法名匹配表达式的用例,如果指定的表达式是被文件名/测试类名包含的,那么文件/测试类中所有的测试方法都会被执行。
# 执行文件名/类名/方法名中包含01的用例
# 通过main函数执行
pytest.main(["-vs", "./product_cases", "-k=01"])
# 通过命令模式执行
pytest -vs ./product_cases -k="01"
指定执行测试用例名称包含01
:
指定执行测试用例名称包含login
:
9)--html:用例执行完成后生成 html 格式的测试报告
pytest -vs --html ./report/result.html
--html+报告存放路径参数
六、用例执行顺序
修改 test_product.py 中测试方法:
def test_product_case():
print("模拟测试产品相关的操作")
def test_case_001():
print("测试方法_001")
def test_case_002():
print("测试方法_002")
def test_case_003():
print("测试方法_003")
def test_case_004():
print("测试方法_004")
def test_case_005():
print("测试方法_005")
1)默认执行顺序
pytest 对于用例的执行顺序是按照从上到下执行的
2) 改变用例的执行顺序
通过装饰器方法@pytest.mark.run()
可以改变用例的执行顺序,参数order=n指定排在第n个执行
# product_cases/test_product.py
import pytest
def test_product_case():
print("模拟测试产品相关的操作")
# 通过装饰器方法 @pytest.mark.run() 可以改变用例的执行顺序
# order参数表示该用例要排在第几个执行
@pytest.mark.run(order=1)
def test_case_002():
print("测试方法_002")
@pytest.mark.run(order=2)
def test_case_003():
print("测试方法_003")
def test_case_004():
print("测试方法_004")
def test_case_005():
print("测试方法_005")
从终端输出的结果可以看到,被装饰器装饰的测试用例都按照了指定的顺序执行,没有被装饰到的用例还是按照从上到下的顺序执行
七、标记函数,分组执行用例
1)装饰器@pytest.mark.name
装饰用例
第一步,使用装饰器@pytest.mark.name
去装饰要执行的用例,其中 name 为自定义的名称
# product_cases/test_product.py
import pytest
# 通过装饰器方法 @pytest.mark.finished标记已完成的用例
@pytest.mark.finished
def test_product_case():
print("模拟测试产品相关的操作")
# 通过装饰器方法 @pytest.mark.unfinished标记未完成功能的用例
@pytest.mark.unfinished
def test_case_002():
print("测试方法_002")
@pytest.mark.unfinished
def test_case_003():
print("测试方法_003")
def test_case_004():
print("测试方法_004")
def test_case_005():
print("测试方法_005")
2)pytest.ini 添加分组配置
第二步,去 pytest.ini 中添加分组配置,配置名必须和装饰器中的 name 值一致3)参数 -m 指定执行用例
第三步,执行时通过参数 -m 指定要执行的用例八、跳过用例
对于某些不想执行的用例,可以使用 pytest 提供的装饰器方法@pytest.mark.skip()
跳过该用例不去执行
1)直接跳过
装饰器语法:@pytest.mark.skip(reason="")
,reason 参数可选,表示跳过该测试方法的原因
2)条件跳过
装饰器语法:@pytest.mark.skipif(判断条件, reason="")
,为测试函数指定被忽略的条件,reason 参数可选
# product_cases/test_product.py
import pytest
version = 1
# V2版本才支持,版本小于V2则跳过不执行
@pytest.mark.skipif(version < 2, reason='not supported until v2')
def test_product_case():
print("模拟测试产品相关的操作")
def test_case_001():
print("测试方法_001")
def test_case_002():
print("测试方法_002")
-
version=1满足条件,跳过不执行满足条件跳过
-
version=2不满足条件,不跳过执行不满足条件不跳过
文章转载参考:http://www.chendacheng.com/content/?category=Pytest%E4%B8%93%E9%A2%98&article=Pytest_01.html