Pytest基础使用
Pytest是一个易用、强大、灵活的功能测试框架,并且兼容unittest和nose的测试用例
- 易用: 用例编写简单, 断言方便
- 强大: 全能的mark, 强大的fixtures
- 灵活: 灵活的执行控制及丰富的插件
安装
pip3 install pytest
用例编写及断言
# filename: test_reg.py
import requests
def test_user_reg(): # 可以不用写类
url = "http://47.94.156.36:5000/api/user/reg/"
data = {"name": "临渊", "password": "123456"}
res = requests.post(url, json=data)
assert '100000' == res.json()['code'] # 断言使用Python原生assert
assert '注册成功' in res.json()['msg']
运行方法
在当前文件所在目录,打开命令行,运行:
pytest test_reg.py
或者在脚本中,导入pytest,使用pytest.main([...])
运行:
...
import pytest
def test_user_reg():
...
if __name__ == '__main__':
pytest.main(['test_reg.py'])
全能的mark
mark主要用来标记用例,通过不同的标记实现不同的运行策略
主要用途:
- 标记和分类用例:
@pytest.mark.level1
- 标记用例执行顺顺序
pytest.mark.run(order=1)
(需安装pytest-ordering) - 标记用例在指定条件下跳过或直接失败
@pytest.mark.skipif()/xfail()
- 标记使用指定fixture(测试准备及清理方法)
@pytest.mark.usefixtures()
- 参数化
@pytest.mark.parametrize
- 标记超时时间
@pytest.mark.timeout(60)
(需安装pytest-timeout) - 标记失败重跑次数
@pytest.mark.flaky(reruns=5, reruns_delay=1)
(需安装pytest-rerunfailures)
标记和分类用例
# 标记用例, 支持多个标记, 运行时可以运行带/不带指定标记的用例
@pytest.mark.apitest
@pytest.mark.level1
def test_user_reg():
...
标记用例在指定条件下跳过或直接失败
db = DB() # 封装的数据对象, 详见之前的文章
# 如果查询到用户存在则跳过用例, 也可以使用@pytest.mark.xfail()置为失败
@pytest.mark.skipif(db.check_user("临渊"))
def test_user_reg():
...
@pytest.mark.incremental # 如果类中某条没过,之后的全部置为失败
class TestReg():
...
标记使用指定fixtures
db=Db() # 封装的数据对象, 详见之前的文章
@pytest.fixture() # 声明为fixture(测试准备/清理)方法
def del_user():
db.del_user_if_exist("临渊") # setup
yield
db.del_user_if_exist("临渊") # teardown
@pytest.mark.usefixtures("del_user")
def test_user_reg():
...
参数化
names = ["羡鱼", "abc123", "admin@123.com"]
@pytest.mark.parametrize("name", names)
def test_user_reg(name): # 接收的变量名要和parametrize的"name"一致
url = 'http://47.94.156.36:5000/api/user/reg/'
data = {"name": name, "password": "123456"}
res = requests.post(url, json=data)
# 执行时会根据数据的数量执行3条用例
标记超时时间
pip3 install pytest-timeout
@pytest.mark.timeout(60)
def test_user_reg(): # 当前用例限定60s超时
...
或命令行使用pytest --timeout=300
限定所有用例
标记失败重跑次数
pip3 install pytest-rerunfailures
@pytest.mark.flaky(reruns=5, reruns_delay=1) # 如果失败则延迟1s后重跑
def test_user_reg() # 最多重跑5次, reruns_delay可以不传
....
或pytest --reruns 5 --reruns-delay 1
强大的fixtures(测试准备/清理)方法
Pytest提供会话(一次测试运行为一个会话)/包/模块/类/方法级别以及用例单独的fixtures方法, 并且支持unittest/nose中的setUpModule/tearDownModule
,setUpClass/tearDownClass
,setUp/tearDown
方法,并且使用更加灵活
unittest/nose中没有会话级的fixtures方法, 同时没有个别用例单独使用的fixtures方法
fixture参数支持scope
(生效范围)和autouse
(自动使用)
生效范围
- session: 会话级, 所有执行的用例
- package: 包级, 当前包所有执行的用例
- module: 模块级
- class: 类级
- function: 方法级
@pytest.fixture(scope="session", autouse=True) # 声明所有执行的用例自动使用
def open_browser():
driver = webdriver.Chrome()
yield driver
driver.quit()
yield之前的为setup方法, 进入范围时执行,yield之后的为teardown方法,离开范围时执行
注: 如果yield前的setup操作出现异常,teardown操作将不再执行, 如果setup操作不稳定,可以使用
addfinalizer
方法确保teardown操作一定被执行
执行顺序
- setup执行顺序按范围从大到小, teardown方法按相反顺序
独立的fixture方法(供某个/某些用例单独使用)
db=Db() # 封装的数据对象, 详见之前的文章
@pytest.fixture() # 声明为fixture(测试准备/清理)方法
def del_user():
db.del_user_if_exist("临渊") # setup
yield
db.del_user_if_exist("临渊") # teardown
def test_user_reg(del_user): # 将fixture方法函数名作为参数使用
... # 和使用@pytest.mark.usefixtures('del_user')作用相同
向fixture方法传递参数及使用返回结果
待补充
...
使用conftest.py
(固定文件名),集中管理fixtures方法
待补充
...
灵活的运行控制
通过pytest ...
命令,可以实现非常灵活的执行控制
- 运行目录及子包下的所有用例:
pytest 目录名
- 运行指定模块所有用例:
pytest test_reg.py
-
pytest test_reg.py::TestClass::test_method
运行指定模块指定类指定用例 - 运行名称包含指定表达式的用例:-k 表达式(支持and or not),如
pytest -k "test_a and test_b"
- 运行指定标签(mark)的用例: -m 标签(支持and or not), 如
pytest -m "apitest and level1"
- 遇到失败后停止:-x/--exitfirst 首次失败后退出(可用于保留出错现场) --maxfails=3 3次失败后退出
- 执行上次失败的用例 --lf/--last-failed
- 先执行上次失败的用例,再执行成功的用例 --ff/--failed-first
- 只收集用例,不执行 --collect-only
- 显示执行最慢的前N条用例:--durations=N
- 并行执行: -n 2 (需安装pytest-xdist)
其它常用参数
-
-q
: 安静模式, 不输出环境信息 -
-v
: 丰富信息模式, 输出更详细的用例执行信息 -
-s
: 显示程序中的print/logging输出 -
pytest --resultlog=./log.txt
生成log -
pytest --junitxml=./log.xml
生成xml报告
丰富的插件
- pytest-html 生成html报告插件
pip3 install pytest-html
pytest test_reg.py --html=report.html
- pytest-timeout 限制用例超时时间
pip3 install pytest-timeout
@pytest.mark.timeout(60)
def test_user_reg(): # 当前用例限定60s超时
...
或 pytest --timeout=300
限定所有用例
- pytest-rerunfailures 失败重试
pip3 install pytest-rerunfailures
@pytest.mark.flaky(reruns=5, reruns_delay=1) # 如果失败则延迟1s后重跑
def test_user_reg() # 最多重跑5次, reruns_delay可以不传
....
或pytest --reruns 5 --reruns-delay 1
- pytest-xdist 多CPU分发并行执行用例
pip3 install pytest-xdist
待补充
...
- 其它
- pytest-selenium
- pytest-bdd