pytest完整
Posted autointerface
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pytest完整相关的知识,希望对你有一定的参考价值。
学习目标
1. 能够安装 pytest 框架
2. 能够了解 pytest 主函数的运行方式
3. 能够掌握 pytest 命令行的运行方式
4. 能够掌握 setup 和 teardown 方法
5. 能够掌握 setup_class 和 teardown_class 方法
6. 能够理解 pytest 配置文件的含义
7. 能够生成 pytest-html 测试报告
8. 能够控制 pytest 函数执行的顺序
9. 能够掌握 pytest 失败重试
10. 能够掌握 pytest 跳过函数
11. 能够掌握 pytest 预期失败
12. 能够掌握 pytest 数据参数化
13. 能够了解 fifixture 的使用
一. Pytest-基本使用
应用场景
pytest 框架可以解决我们多个测试脚本一起执行的问题
1.1 安装和介绍
概念
pytest 是 python 的一种单元测试框架,同自带的 Unittest 测试框架类似,相比于 Unittest 框架使用起来更简洁,
效率更高。
特点
1. 非常容易上手,入门简单,文档丰富,文档中有很多实例可以参考
2. 支持简单的单元测试和复杂的功能测试
3. 支持参数化
4. 执行测试过程中可以将某些测试跳过,或者对某些预期失败的 Case 标记成失败
5. 支持重复执行失败的 Case
6. 支持运行由 Nose,Unittest 编写的测试 Case
7. 具有很多第三方插件,并且可以自定义扩展
8. 方便的和持续集成工具集成
安装
安装校验
1. 进入命令行 pip install pytest
2. 输入命令 pytest --version 会展示当前已安装版本
1.2 运行方式
代码准备
test_login.py
运行方式分为两种
1. 命令行模式【建议】命令行中执行 pytest -s test_login.py
2. 主函数模式
在 test_login.py 文件中增加主函数
if __name__ == ‘__main__‘:
pytest.main(["-s", "login.py"])
-s 表示支持控制台打印,如果不加,print 不会出现任何内容
运行结果
test_login.py ------->test_a
.------->test_b
F
. 表示成功
F 表示失败
小结
建议使用命令行的形式运行,对比主函数模式更加方便
1.3 setup 和 teardown
应用场景
pytest 在运行自动化脚本的前后会执行两个特殊的方法,分别是 setup 和 teardown 。在执行脚本之前会执行 setup
方法,在执行脚本之后会执行 teardown 方法。有了这两个方法,我们可以在 setup 中进行获取驱动对象的操作,在
teardown 中进行关闭驱动对象的操作。
1.3.1 函数级别方法
运行于测试方法的始末,运行一次测试函数会运行一次 setup 和 teardown。
示例代码
class TestLogin:
def test_a(self): # test开头的测试函数
print("------->test_a")
assert 1 # 断言成功
def test_b(self):
print("------->test_b")
assert 0 # 断言失败
def test_a(self):
print("------->test_a")
def test_b(self):
print("------->test_b")
执行结果
scripts/test_login.py ------->setup_method # 第一次 setup()
------->test_a
.------->teardown_method # 第一次 teardown()
------->setup_method # 第二次 setup()
------->test_b
.------->teardown_method # 第二次 teardown()
1.3.2 类级别方法
运行于测试类的始末,在一个测试内只运行一次 setup_class 和 teardown_class,不关心测试类内有多少个测试函数。
示例代码
class TestLogin:
# 测试类级开始
def setup_class(self):
print("------->setup_class")
# 测试类级结束
def teardown_class(self):
print("------->teardown_class")
def test_a(self):
print("------->test_a")
def test_b(self):
print("------->test_b")
执行结果scripts/test_login.py ------->setup_class # 第一次 setup_class()
------->test_a
.------->test_b
.------->teardown_class # 第一次 teardown_class()
1.4 配置文件
应用场景
使用配置文件后可以快速的使用配置的项来选择执行哪些测试模块。
使用方式
1. 项目下新建 scripts 模块
2. 将测试脚本文件放到 scripts 中
3. pytest 的配置文件放在自动化项目目录下
4. 名称为 pytest.ini
5. 命令行运行时会使用该配置文件中的配置
6. 第一行内容为 [pytest]
示例
[pytest]
# 添加命令行参数
addopts = -s
# 文件搜索路径
testpaths = ./scripts
# 文件名称
python_files = test_*.py
# 类名称
python_classes = Test*
# 方法名称
python_functions = test_*
addopts = -s
表示命令行参数
testpaths,python_fifiles,python_classes,python_functions
表示 哪一个文件夹 下的 哪一个文件 下的 哪一个类 下的 哪一个函数
表示执行 scripts 文件夹下的 test_ 开头 .py 结尾的文件下的 Test 开头的类下的 test_开头的函数
def test_a(self):
print("------->test_a")
def test_b(self):
print("------->test_b")
v>
二. Pytest-常用插件
插件列表网址:https://plugincompat.herokuapp.com 包含很多插件包,大家可依据工作的需求选择使用。
2.1 测试报告
应用场景
自动化测试脚本最终执行是通过还是不通过,需要通过测试报告进行体现。
安装
使用命令 pip3 install pytest-html 进行安装
使用
在配置文件中的命令行参数中增加 --html=用户路径/report.html
示例
pytest.ini
addopts = -s --html=report/report.html
结果
在项目目录下会对一个 report 文件夹,里面有个 report.html 即为测试报告
2.2 控制函数执行顺序
应用场景
现实生活中,如果想下订单,必须先登录,我们可以通过插件的形式来控制函数执行的顺序。
安装
使用命令 pip3 install pytest-ordering 进行安装
使用
1. 标记于被测试函数,@pytest.mark.run(order=x)
2. 根据order传入的参数来解决运行顺序
3. order值全为正数或全为负数时,运行顺序:值越小,优先级越高
4. 正数和负数同时存在:正数优先级高
示例
import pytest
class TestLogin:
def test_hello_001(self):
print("test_hello_001")
@pytest.mark.run(order=1)
def test_hello_002(self):
print("test_hello_002")
@pytest.mark.run(order=2)
def test_hello_003(self):
print("test_hello_003")
结果
scripts/test_login.py test_hello_002 # 先运行2
.test_hello_003 # 再运行3
.test_hello_001
2.3 失败重试
应用场景
自动化测试脚本可能会使用到网络,如果网络不好可能最终会使脚本不通过。像这种情况可能并不是脚本本身的问
题,仅仅是因为网络忽快忽慢,那么我们可以使用失败重试的插件,当失败后尝试再次运行。一般情况最终成功可以
视为成功,但最好进行进行排查时候是脚本问题。
安装
使用命令 pip3 install pytest-rerunfailures 进行安装
使用
在配置文件中的命令行参数中增加 --reruns n
示例
pytest.ini
addopts = -s --reruns 3
test_login.py
class TestLogin:
def test_a(self): # test开头的测试函数
print("------->test_a")
assert 1 # 断言成功
def test_b(self):
print("------->test_b")
assert 0 # 断言失败
结果
scripts/test_login.py ------->test_a
.------->test_b
R------->test_b
R------->test_b
R------->test_b
F
R 表示重试
注意点
重试时,如果脚本通过,那么后续不再重试
三. Pytest-高级用法
3.1 跳过测试函数
应用场景
同一个软件在不同的设备上可能会有不同的效果,比如,ios 的 3d touch 操作是需要 6s 以上设备支持的,6 和 6s都可以安装同一款应用,如果设备不支持,那么根本没有必要去测试这个功能。此时,我们可以让这种函数进行跳过。
方法名
# 跳过测试函数
# 参数:
#condition:跳过的条件,必传参数 reason:标注原因,必传参数
@pytest.mark.skipif(condition, reason=None)
使用方式
在需要跳过的测试脚本之上加上装饰器 @pytest.mark.skipif(condition, reason="xxx")
示例
import pytest
class TestLogin:
def test_a(self): # test开头的测试函数
print("------->test_a")
assert 1 # 断言成功
@pytest.mark.skipif(condition=True, reason="xxx")
def test_b(self):
print("------->test_b")
assert 0 # 断言失败
结果
scripts/test_login.py ------->test_a
.s
3.2 预期失败
应用场景
比如,注册时要求用户名为 6 - 10 位,如果我们传入一个 12 位的用户名,此时可以使用预期失败。
方法名
# 预期失败
# 参数:condition:跳过的条件,必传参数 reason:标注原因,必传参数
@pytest.mark.xfail(condition=None, reason=None, raises=None, run=True, strict=False)
使用方式
在需要标记预期失败的测试脚本之上加上装饰器 @pytest.mark.xfail(condition, reason="xx")
示例
import pytest
class TestLogin:
def test_a(self): # test开头的测试函数
print("------->test_a")
assert 1 # 断言成功
@pytest.mark.xfail(condition=True, reason="xx")
def test_b(self):
print("------->test_b")
assert 0
@pytest.mark.xfail(condition=True, reason="xx")
def test_c(self):
print("------->test_c")
assert 1
结果
scripts/test_login.py ------->test_a
.------->test_b
x------->test_c
X
x 表示预期失败结果失败 不算是bug
X 表示预期失败结果成功 算是bug
v>
3.3 数据参数化
应用场景
登录功能都是输入用户名,输入密码,点击登录。但登录的用户名和密码如果想测试多个值是没有办法用普通的操作
实现的。数据参数化可以帮我实现这样的效果。
方法名
# 数据参数化 参数:argnames:参数名 argvalues:参数对应值,类型必须为可迭代类型,一般使用list
@pytest.mark.parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
一个参数使用方式
1. argnames 为字符串类型,根据需求决定何时的参数名
2. argvalues 为列表类型,根据需求决定列表元素中的内容
3. 在测试脚本中,参数,名字与 argnames 保持一致
4. 在测试脚本中正常使用
argvalues 列表有多少个内容,这个脚本就会运行几次
import pytest
class TestLogin:
@pytest.mark.parametrize("name", ["xiaoming", "xiaohong"])
def test_a(self, name):
print(name)
assert 1
scripts/test_login.py xiaoming
.xiaohong
.
多个参数使用方式
示例
import pytest
class TestLogin:
@pytest.mark.parametrize(("username", "password"), [("zhangsan", "zhangsan123"),
("xiaoming", "xiaoming123")])
def test_a(self, username, password):
print(username)
print(password)
assert 1
结果
scripts/test_login.py zhangsan
zhangsan123
.xiaoming
xiaoming123
.
多个参数还可以将装饰器写成 @pytest.mark.parametrize("username,password", [("zhangsan",
"zhangsan123"), ("xiaoming", "xiaoming123")]) 效果是一样的。
四. Pytest-fifixture
应用场景
fifixture 修饰器来标记固定的工厂函数,在其他函数,类调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作。
4.1 使用方式
使用方式有两种
1. 通过参数引用
2. 通过函数引用
4.1.1 通过参数引用
示例
import pytest
class TestLogin:
@pytest.fixture()
def before(self):
print("------->before")
def test_a(self, before): # test_a方法传入了被fixture标识的函数,已变量的形式
print("------->test_a")
assert 1
运行结果
scripts/test_login.py ------->before
------->test_a
4.1.2 通过函数引用
示例
import pytest
class TestLogin:
@pytest.fixture()
def before(self):
print("------->before")
@pytest.mark.usefixtures("before") # 使用函数引用
def test_a(self):
print("------->test_a")
assert 1
运行结果
scripts/test_login.py ------->before
------->test_a
4.2 参数
4.2.1 默认运行
参数名
@pytest.fixture(autouse=False)
示例
import pytest
class TestLogin:
@pytest.fixture(autouse=True)
def before(self):
print("------->before")
def test_a(self):
print("------->test_a")
assert 1
def test_b(self):
print("------->test_b")
assert 1
运行结果
scripts/test_login.py ------->before
------->test_a
.------->before
------->test_b
.
v>
4.2.2 作用域
参数名
@pytest.fixture(scope="function")
默认作用域为 函数 级别,在设置自动运行的情况,所有的测试脚本都会运行 fifixture,如果想某个类只运行一次,可
以将作用域改为 class。但前提一定是将 fifixture 函数写在类的外面。
示例
import pytest
@pytest.fixture(autouse=True, scope="class")
def before():
print("------->before")
class TestLogin:
def test_a(self):
print("------->test_a")
assert 1
def test_b(self):
print("------->test_b")
assert 1
运行结果
scripts/test_login.py ------->before
------->test_a
.------->test_b
.
4.2.3 参数化
参数名
@pytest.fixture(params=None)
params 是一个列表,列表中有多少元素,脚本就会运行多少次。如果想获取 params 中的数据,需要在 fifixture 里面加上 request 参数,这个参数名必须叫做 request ,通过这个
参数的 .param 属性获取值。
示例
import pytest
class TestLogin:
@pytest.fixture(params=[1, 2])
def before(self, request):
print("------->before")
print(request.param)
def test_a(self, before):
print("------->test_a")
assert 1
运行结果
scripts/test_login.py ------->before
1
------->test_a
.------->before
2
------->test_a
.
4.3 返回值
fifixture 函数是允许有返回值,使用参数的形式进行 fifixture 的引用,可以直接使用 fifixture 的返回值。
示例
import pytest
v>
class TestLogin:
@pytest.fixture()
def before(self):
print("------->before")
return 20
def test_a(self, before):
print("------->test_a")
print(before)
assert 1
运行结果
scripts/test_login.py ------->before
------->test_a
20
.
扩展
如果使用 fifixture 参数化的同时也使用了脚本的参数化,可以达到 “两两” 组合的效果。比如,fifixture的parmas里面
有 3 个元素,脚本的参数化里面有 4 个元素,那么这个脚本会运行 12 次。
示例
import pytest
class TestLogin:
@pytest.fixture(params=[1, 2])
def before(self, request):
print("------->before")
return request.param
@pytest.mark.parametrize("name", [3, 4])
def test_a(self, before, name):
print("------->test_a")
print("%d - %d" % (before, name))
assert 1
scripts/test_login.py ------->before
------->test_a
1 - 3
.------->before
------->test_a
1 - 4
.------->before
------->test_a
2 - 3
.------->before
------->test_a
2 - 4
以上是关于pytest完整的主要内容,如果未能解决你的问题,请参考以下文章
pytest接口自动化测试框架 | @pytest.fixture()装饰器