pytest简介
pytest命令行参数
setup和teardown调用顺序
pytest测试用例的执行顺序控制:pytest-ordering插件
pytes概述
pytest 与 Python 自带的 Unittest 测试框架类似,但 pytest 使用起来更灵活和高效,并且兼容 unittest 框架。pytest 有以下实用特性:
- pytest 支持简单的单元测试和复杂的功能测试
- 支持参数化,数据驱动,避免冗余代码
- pytest 可自动重试失败的测试用例,分级测试用例快速迭代
- 可以结合 Requests 实现接口测试
- 结合 Selenium、Appium 实现自动化功能测试
- 使用 pytest 结合 Allure 集成到 Jenkins 中可以实现持续集成,生成测试报告
- pytest 有丰富的第三方插件:pytest插件
官方文档
pytest安装和基本使用
pytest安装
pip install -U pytest
pytest命令行
在包含test_*.py
文件所在目录执行pytest
命令,pytest
会找当前目录以及递查找子目录下所有的 test_*.py
(或*_test.py
) 的文件,把其当作测试文件。在这些文件里,pytest
会收集符合编写规范的函数,类以及方法,当作测试用例并且执行
命令行参数:
- 无参数:执行
pytest
或者py.test
,读取路径下所有符合规则的文件,类,方法,函数全部执行 - 运行模式:pytest 提供了多种运行模式,让开发和调试更得心应手。 在编写测试用例的时候,经常会单独调试某个类,或者某个方法。也可以使用 Pycharm 里面自带的调试方式,点击用例方法名前面的绿色按钮,也可以使用命令行的方式单独运行某个用例
pytest 文件名.py # 单独执行某个Python文件
pytest 文件名.py::类名 # 单独执行某个文件中的类
pytest 文件名.py::类名::方法名 # 单独执行类中的某个方法 |
- 其他
参数 | 说明 | 使用方法 | 应用场景 |
---|---|---|---|
-v | 打印详细运行日志信息 | pytest -v | 一般在调试的时候加上这个参数,终端会打印出每条用例的详细日志信息,方便定位问题。 |
-s | 带控制台输出结果 | pytest -s | 当你的代码里面有 print 输出语句,如果想在运行结果中打印 print 输出的代码,在运行的时候可以添加 -s 参数,一般在调试的时候使用 |
-k | 跳过运行某个或者某些用例 | pytest -k '类名' ;pytest -k '方法名' ;pytest -k '类名 and not 方法名' # 运行类里所有的方法,不包含某个方法 |
在测试场景中,开发人员有一部分功能代码还没实现,测试人员已经将测试用例设计出来,或者测试人员发现了某功能上的 bug 需要开发人员修复之后再测试这部分有缺陷的测试用例,可以将这部分测试用例在运行的时候暂时跳过,等功能实现或者 bug 解决之后再加入运行。 |
-x | 遇到用例失败立即停止运行 | pytest -x | 在回归测试过程中,假如一共有10条基础用例,当开发人员打完包提交测试的时候,需要先运行这10条基础用例,全部通过才能提交给测试人员正式测试。如果有一条用例失败,都将这个版本打回给开发人员。这时就可以添加 -x 参数,一旦发现有失败的用例即中止运行。 |
--maxfail | 用例失败个数达到阀值停止运行 | pytest --maxfail=[num] | 在回归测试过程中,假如一共有10条基础用例,当开发人员打完包提交测试的时候,需要先运行这10条基础用例,全部通过才能提交给测试人员正式测试。如果运行过程中有 [num] 条用例失败,即中止运行,后面测试用例都放弃执行,直接退出。这时可以使用 --maxfail 参数。 |
-m | 运行有 @pytest.mark.[标记名] 这个标记的测试用例 | pytest -m [标记名] | 在自动化测试过程中可以将测试用例添加标签进行分类,比如登录功能、搜索功能、购物车功能、订单结算功能等,在运行的时候可以只运行某个功能的所有的测试用例,比如这个版本只想验证登录功能,那就在所有登录功能的测试用例方法上面加上装饰符 @pytest.mark.login ,运行的时候使用命令添加一个 -m 参数,例如执行 pytest -m login 命令就可以只执行登录功能这部分的测试用例。 |
在pycharm中基本使用
打开 Pycharm -> Preferences-> Tools -> Python Integrated Tools -> Testing: pytest
如下例子test_add.py文件:
def add(x, y):
return x + y
def test_add():
assert add(1, 2) == 3
assert add(100, 1) == 101
class TestCase:
def test_in(self):
assert 'a' in 'baidu'
def test_hasattr(self):
a = '1000'
assert isinstance(a, (int,))
用例编写规范:
- 测试文件以 test_ 开头(常用),以 _test 结尾也可以
- 测试类以 Test 开头,并且不能带有 init 方法
- 测试函数以 test_ 开头
- 断言使用基本的 assert 即可
pytest 框架结构和执行顺序
pytest框架结构
与 unittest 类似,执行用例前后会执行 setup,teardown 来增加用例的前置和后置条件。
pytest 框架中使用 setup,teardown 更灵活,按照用例运行级别可以分为以下几类:
- 模块级(setup_module/teardown_module)在模块始末调用
- 函数级(setup_function/teardown_function)在函数始末调用(在类外部)
- 类级(setup_class/teardown_class)在类始末调用(在类内)
- 方法级(setup_method/teardown_methond)在方法始末调用(在类内)
- 方法级(setup/teardown)在方法始末调用(在类内)
setup和teardown调用顺序
setup_module > setup_class >setup_method > setup > teardown > teardown_method > teardown_class > teardown_module
参考如下例子验证调用顺序:
def setup_module():
print("\n【start】:模块级setup_module,只执行一次,当有多个测试类的时候使用")
def teardown_module():
print("\n【end】teardown_module,只执行一次,当有多个测试类的时候使用")
class TestPytest1:
@classmethod
def setup_class(cls):
print("\n【1】:类1中的类级别setup_class1,只执行一次")
@classmethod
def teardown_class(cls):
print("\n【5】类1中的类级别teardown_class1,只执行一次")
def setup_method(self):
print("\n【2-1】【2-2】:类1中的方法级setup_method1,每个测试方法都执行一次")
def teardown_method(self):
print("【4-1】【4-2】:类1中的方法级teardown_method1,每个测试方法都执行一次")
def test_one(self):
print("【3-1】类1中的测试用例1:test_one_in_class1,测试用例1")
def test_two(self):
print("【3-2】类1中的测试用例2:test_two_in_class1,测试用例2")
class TestPytest2:
@classmethod
def setup_class(cls):
print("\n【a】类2中的类级别setup_class2,只执行一次")
@classmethod
def teardown_class(cls):
print("\n【e】类2中的类级teardown_class2,只执行一次")
def setup_method(self):
print("\n【b-1】【b-2】类2中的方法级setup_method2,每个测试方法都执行一次")
def teardown_method(self):
print("【d-1】【d-2】类2中的方法级teardown_method2,每个测试方法都执行一次")
def test_one(self):
print("【c-1】类2中的测试用例1:test_one,测试用例1")
def test_two(self):
print("【c-2】类2中的测试用例2:test_two,测试用例2")
执行结果如下:
============================= test session starts ==============================
platform darwin -- Python 3.8.5, pytest-6.1.0, py-1.9.0, pluggy-0.13.1 -- /Users/tina/venv/test/bin/python3.8
cachedir: .pytest_cache
rootdir: /Users/tina/PycharmProjects/pytest_test
collecting ... collected 4 items
test_order.py::TestPytest1::test_one
【start】:模块级setup_module,只执行一次,当有多个测试类的时候使用
【1】:类1中的类级别setup_class1,只执行一次
【2-1】【2-2】:类1中的方法级setup_method1,每个测试方法都执行一次
PASSED [ 25%]【3-1】类1中的测试用例1:test_one_in_class1,测试用例1
【4-1】【4-2】:类1中的方法级teardown_method1,每个测试方法都执行一次
test_order.py::TestPytest1::test_two
【2-1】【2-2】:类1中的方法级setup_method1,每个测试方法都执行一次
PASSED [ 50%]【3-2】类1中的测试用例2:test_two_in_class1,测试用例2
【4-1】【4-2】:类1中的方法级teardown_method1,每个测试方法都执行一次
【5】类1中的类级别teardown_class1,只执行一次
test_order.py::TestPytest2::test_one
【a】类2中的类级别setup_class2,只执行一次
【b-1】【b-2】类2中的方法级setup_method2,每个测试方法都执行一次
PASSED [ 75%]【c-1】类2中的测试用例1:test_one,测试用例1
【d-1】【d-2】类2中的方法级teardown_method2,每个测试方法都执行一次
test_order.py::TestPytest2::test_two
【b-1】【b-2】类2中的方法级setup_method2,每个测试方法都执行一次
PASSED [100%]【c-2】类2中的测试用例2:test_two,测试用例2
【d-1】【d-2】类2中的方法级teardown_method2,每个测试方法都执行一次
【e】类2中的类级teardown_class2,只执行一次
【end】teardown_module,只执行一次,当有多个测试类的时候使用
============================== 4 passed in 0.02s ===============================
Process finished with exit code 0
测试用例的执行顺序控制
pytest 加载所有的测试用例是乱序的。
在运行测试用例时,如有些场景需要先登陆才能执行后续流程,因此需要指定测试用例顺序,这里可以通过pytest-ordering插件来完成。只需要在测试用例的方法前面加上装饰器 @pytest.mark.run(order=[num])
设置order的对应的num值,它就可以按照 num 的大小顺序来执行。
- 安装插件
pip install pytest-ordering
- 验证示例
import pytest
class TestPytest(object):
@pytest.mark.run(order=-1)
def test_two(self):
print("【-1】test_two测试用例")
@pytest.mark.run(order=3)
def test_one(self):
print("【3】test_one测试用例")
@pytest.mark.run(order=1)
def test_three(self):
print("【1】test_three测试用例")
@pytest.mark.run(order=-4)
def test_four(self):
print("【-4】test_four测试用例")
@pytest.mark.run(order=0)
def test_five(self):
print("【0】test_five测试用例")
执行结果:
test_pytest_order.py::TestPytest::test_five PASSED [ 20%]【0】test_five测试用例
test_pytest_order.py::TestPytest::test_three PASSED [ 40%]【1】test_three测试用例
test_pytest_order.py::TestPytest::test_one PASSED [ 60%]【3】test_one测试用例
test_pytest_order.py::TestPytest::test_four PASSED [ 80%]【-4】test_four测试用例
test_pytest_order.py::TestPytest::test_two PASSED [100%]【-1】test_two测试用例
执行时以 order 的顺序执行:order=0 -> 1 -> 3 -> -4 -> -1 (正数小到大 -> 负数小到大)