官方文档:Full pytest documentation — pytest documentationhttps://docs.pytest.org/en/latest/contents.html
plugin解读:https://github.com/potatoImp/pytestCodeParsinghttps://github.com/potatoImp/pytestCodeParsing
优秀文章参考:基于 Pytest 框架的自动化测试开发实践 (万字长文入门篇) · TesterHomehttps://testerhome.com/topics/23441
基本逻辑:前置脚本失败,用例和后置脚本不执行,用例结果error;用例失败,前后置脚本执行,用例结果failed;后置脚本失败,用例结果1passed,1error
一、运行方式
命令行方式
1.pytest -sv:-s打印用例中print内容,-v打印用例文件路径、类、方法信息
2.pytest -n 次数:多线程或者分布式???
3.pytest --reruns 次数:失败用例重复跑几次
4.python -m pytest:模块化执行
python -m把当前工作目录当作模块执行,解决import工作目录模块报错
5.
pytest 目录:执行目录下符合条件的用例
pytest 目录\文件.py::类(Test*)::方法(test_*):执行一个类或者一个方法
pytest -k "名字":根据名字执行
pytest -m:标签执行
pytest 目录\文件.py:指定模块执行
6.pytest -m:标签执行
@pytest.mark.名称 #下面接类或者方法,给类、方法增加标签
class类或者def用例
pytestmark = pytest.mark.名称 #模块增加标签(模块指整个文件)
pytest -m 名称 #执行调用标签
这样使用marker未注册在执行后会警告,PytestUnknownMarkWarning,在ini文件中注册
pytest.ini配置文件运行
[pytest]
#命令行参数,用空格分割
addopts = -vs -reruns 2 -m "smoke or wait"
#测试用例文件夹,可自己配置
testpaths = ./testcase
#配置测试搜索的模块文件名称
python_files = test*.py
#配置测试搜索的测试类名
python_classes = Test*
#配置测试搜索的测试函数名
python_functions = test
#mark运行,不加有warning
markers =
smoke:function test
wait:wait test
"""
开头必须是[pytest]
文件放在项目根目录下
notepad++打开后选择ansi编码
"""
二、fixture
@pytest.fixture
-
fixture是一个函数,在函数上添加注解
@pytest.fixture
来定义 -
定义在conftest.py中,无需import就可以调用
-
定义在其他文件中,import后也可以调用
-
定义在相同文件中,直接调用
执行顺序
# fixtures documentation order example
order = []
@pytest.fixture(scope="session")
def s1():
order.append("s1")
@pytest.fixture(scope="module")
def m1():
order.append("m1")
@pytest.fixture
def f1(f3):
"""
f1依赖f3
fixture装饰的函数入参,只能是其他fixture。
"""
order.append("f1")
@pytest.fixture
def f3():
order.append("f3")
@pytest.fixture(autouse=True)
def a1():
order.append("a1")
@pytest.fixture
def f2():
order.append("f2")
def test_order(f1, m1, f2, s1):
assert order == ["s1", "m1", "a1", "f3", "f1", "f2"]
"""
session>module>class>function
默认fixture是scope = function
如果scope相同,就按test调用先后顺序,以及fixture之间的依赖关系。
autouse的fixture会优先于相同scope的其他fixture。
"""
fixture嵌套
@pytest.fixture()
def a():
print("1步骤")
@pytest.fixture()
def b(a):
print("2步骤")
def test_order(b):
pass
"""
输出:1步骤\n2步骤
fixture装饰的函数入参,只能是其他fixture。
"""
request
相当于pytest的内置fixture
request.param获取测试的数据,实现fixture参数化
data = [{"user": "admin1", "pwd": "111"}, {"user": "admin2", "pwd": "222"}, {"user": "admin3", "pwd": "333"}]
@pytest.fixture(params=data)
def test(request): #request不能自动联想
data = request.param["user"]
return data
def test_compare(test):
data = test #这里test理解为request类的实例化
print(data)
"""
输出3次user1、user2、user3
"""
request.config获取配置文件参数
#conftest.py
def pytest_addoption(parser):
parser.addoption(
"--whysohard", action="store", default="777", help="pytest为什么这么难啊"
)
@pytest.fixture()
def test(request): #相当于fixture嵌套
return request.config.getoption("--whysohard")
#reture request.comfig.getoption("whysohard")用法一样,命令行参数前不用--
class Test_test:
def testcase1(self,request):
data = request.config.getoption("--whysohard")
print(data)
def testcase2(self,test):
data = test
print(data)
"""
这里用request或者fixture名称都可以
"""
request.module反向获取用例中
@pytest.fixture(scope="module")
def smtp(request):
server = getattr(request.module, "smtpserver", "开始了没有啊")
print(server)
yield
print("结束了")
smtpserver = "开始了"
def test_showhelo(smtp):
print("正在执行")
request成员对象
@pytest.fixture(autouse=True)
def print_request(request):
print("\n=======================request start=================================")
print(request.module)
print(request.function)
print(request.cls)
print(request.fspath)
print(request.fixturenames)
print(request.fixturename)
print(request.scope)
print("\n=======================request end=================================")
def test_answer_1(request):
pass
"""
输出:
=======================request start=================================
<module 'web.cases.module2.test_1' from 'D:\\web\\cases\\module2\\test_1.py'>
<function test_answer_1 at 0x0000012D1C9FD9D8>
None
D:\web\cases\module2\test_1.py
['_verify_url', 'base_url', '__pytest_repeat_step_number', 'show_request', 'request']
show_request
function
=======================request end=================================
"""
三、marker
usefixtures 、filterwarnings 、skip 、skipif 、xfail五种用法
自定义marker见一.6
四、参数化
1.@pytest.mark.parametrize()
多个变量用tuple,多个tuple用list
@pytest.mark.parametrize(("num1", "num2", "exp"), [(1, 2, 3), (2, 3, 5), (2, 1, 3)])
def testcase(num1, num2, exp):
result = num1 + num2
assert result == exp
2.@pytest.fixture()
见request.param用法
3.参数化后对某一用例添加marker
参数化后会生成多个tests,如果有些test需要marker,可以用pytest.param来添加
marker方式
@pytest.mark.parametrize(
"test_input,expected",
[("3+5", 8), ("2+4", 6), pytest.param("6*9", 42, marks=pytest.mark.xfail)],
)
def test_eval(test_input, expected):
assert eval(test_input) == expected
fixture方式
@pytest.fixture(params=[0, 1, pytest.param(2, marks=pytest.mark.skip)])
def data_set(request):
return request.param
def test_data(data_set):
data = data_set
print(data)
4.pytest_generate_tests
用来自定义参数化方案
def pytest_generate_tests(metafunc):
"""
metafunc有5个属性,fixturenames,module,config,function,cls
metafunc.fixturenames:参数化收集时的参数名称
metafunc.module:使用参数名称进行参数化的测试用例所在的模块d对象
metafunc.config:测试用例会话
metafunc.function:测试用例对象,即函数或方法对象
metafunc.cls: 测试用例所属的类的类对象
"""
test_method_name = metafunc.function.__name__
test_class_name = metafunc.cls.__name__
param = get_arg(test_class_name, test_method_name)
// *param 传入两个参数:1.元组 2.列表嵌套元组
metafunc.parametrize(*param)
def get_arg(test_class_name, test_method_name):
# test_class_name = self.__class__.__name__
if test_class_name.startswith("TestApp"):
data = yaml_metis_app_android_data[test_class_name][test_method_name]
else:
data = yaml_metis_web_case[test_class_name][test_method_name]
arg_values = arg_names = []
if isinstance(data, dict):
arg_names = tuple(data.keys()) // tuple() 转换成元组数据
# arg_names = ",".join(data.keys())
arg_values.append(tuple((data.values())))
elif isinstance(data, list):
item = data[0]
arg_names = tuple(item.keys())
for d in data:
arg_values.append(tuple((d.values())))
return arg_names, arg_values
其他
1.pycharm使用pytest执行
file-setting-Python Intergrated Tools(或者直接搜pytest)选择pytest执行,否则默认为unittest方式执行
删除其他configuration,默认使用pytest执行