介绍
1.pytest 是python的一种单元测试框架,同自带的 unittest 测试框架类似,但更简洁,效率更高。
2.特点:
- 易上手
- 支持单元测试和功能测试
- 支持参数化
- 执行测试过程中可以将某些测试跳过,或对某些预测失败的Case标记为失败
- 支持重复执行失败的Case
- 支持运行由Nose,Unittest编写的测试Case
- 有很多第三方插件,且可以自定义扩展
- 方便和持续集成工具集成
3.安装 pip install pytest
使用方法
import pytest
def test_a():
print("1")
return 1 * 0
def test_b():
print("2")
return 1 / 0
if __name__ == '__main__':
pytest.main()
运行结果:
注意:
未配置文件时,函数必须以 test 开头。
if __name__ == '__main__':
pytest.main(["-s"])
打印出 test_a() 函数结果。
也可以在当前目录使用控制台:pytest -s
if __name__ == '__main__':
pytest.main(["-s", "test02.py"])
制定后只测试 test02.py 的运行结果,不然会将 test01.py 也一同测试。
默认:如果只运行当前文件,则编写 pytest.main() 函数;如果想运行当前文件夹下所有文件,则使用控制台命令。
1.配置 pytest 文件
默认规则
模块:从测试目录或当前目录中,递归寻找 test_*.py
或 *_test.py
类:以上模块中的test开头的类,且没有初始化__init__
方法
函数及方法:以上模块或类中,test开头的函数或方法
其他:unittest定义的测试用例类
pytest.ini
默认配置文件
[pytest]
addopts = -s
testpaths = ./
python_files = test_*.py *test.py
python_classes = Test*
python_functions = test_*
2.断言
import pytest
def test_a():
print("1")
assert 1==1
def test_b():
print("2")
assert "a" in "hello"
if __name__ == '__main__':
pytest.main(["-s", "test_py03.py"])
运行结果:
3.标记
标记跳过测试:原因可以不写
标记预期失败
import pytest
def test_a():
print("1")
return 1 + 1
# 标记跳过
@pytest.mark.skipif(reason='我想跳过')
def test_b():
print("2")
return 1 / 0
# 标记预期失败
@pytest.mark.xfail(raises=ZeroDivisionError)
def test_c():
print("3")
return 1 / 0
if __name__ == '__main__':
pytest.main(["-s", "test_py04.py"])
4.参数化
import pytest
# 传参
@pytest.mark.parametrize(["a", "b"], [(50, 60), (1, 2)])
def test_a(a, b):
print("ok")
assert a + b > 100
if __name__ == '__main__':
pytest.main(["-s", "test_py05.py"])
夹具
1.作用:在测试之前和之后执行,用于固定测试环境,及清理回收测试资源。
基础方式
级别:
def setup_module/class/method/function(module/cls/self,method/fun):
pass
def setup_module/class/method/function(module/cls/self,method/fun):
pass
不注明时,默认是方法级别。
- 模块级
- 类级
- 方法级
- 函数级
import pytest
def setup_module(args):
print("setup_module", args)
def teardown_module(args):
print("teardown_module", args)
def test_func_a():
print("func_a")
class Test0ne():
TAG = "A"
def test_one(self):
print(self.TAG + 'test_1')
def test_two(self):
print(self.TAG + 'test_2')
if __name__ == '__main__':
pytest.main(["-s", "test_py06.py"])
fixture装饰器
可以传参,且可以具备返回值。
# fixture装饰器使用夹具
import pytest
@pytest.fixture()
def before():
print("before")
@pytest.mark.usefixtures("before")
def test_a():
print("a")
return 1
@pytest.fixture()
def login():
print("login")
return "login"
@pytest.mark.usefixtures("login")
def test_b(login):
print("b", login)
return 1
@pytest.fixture(params=[1, 2, 3])
def init_data(request):
print("init_data", request.param)
return request.param
def test_data(init_data):
assert init_data > 1
if __name__ == '__main__':
pytest.main(["-s", "test_py07.py"])
def fixture(
scope="function", # 夹具级别
params=None, # 参数
autouse=False, # 是否自动使用
ids=None,
name=None
):
插件
1.html报告
pip install pytest-html
[pytest]
addopts = -s --html=./report.html
2.指定执行顺序
pip install pytest-ordering
@pytest.mark.run(order=0)
# 正数标记>未标记函数>负数标记:在各阶段数字越小,优先级越高
3.失败重试
pip install pytest-rerunfailures
[pytest]
addopts = -s --html=./report.html --reruns 5
failed,重新运行5次