文章目录
一、背景:
我们平时使用pytest执行完接口自动化后,可能还要对接邮箱现在更多的是到企业微信、钉钉等发送用例执行情况给到同事,本篇主要介绍如何搜集用例的这些执行情况
二、钩子函数:
2.1、创建位置:
项目主路径下-创建conftes.py文件,这样不用做任何钩子函数自动加载
2.2、代码介绍:
在用例执行完成后会自动打印出结果
def pytest_terminal_summary(terminalreporter, exitstatus, config):
'''
收集用例执行结果
:param terminalreporter:
:param exitstatus:
:param config:
:return:
'''
print("捕捉用例的通过对象", len(terminalreporter.stats.get("passed", [])))
print("捕捉用例的失败对象", len(terminalreporter.stats.get("failed", [])))
print("捕捉用例的跳过对象", len(terminalreporter.stats.get("skipped", [])))
faild_list = list()
faild_object = terminalreporter.stats.get("passed", [])
print("捕捉用例总数", terminalreporter._numcollected)
print("捕捉所有对象", terminalreporter.stats)
for i in faild_object:
print("获取失败用例集对象i:", i)
print("获取失败用例集对象名称location", i.location)
faild_list.append(i.location[-1])
print("获取失败用例集日志", i.longrepr)
2.3、按各域返回用例情况:
def pytest_terminal_summary(terminalreporter, exitstatus, config):
'''
收集用例执行结果
:param terminalreporter:
:param exitstatus:
:param config:
:return:
'''
print("捕捉用例的通过对象", len(terminalreporter.stats.get("passed", [])))
print("捕捉用例的失败对象", len(terminalreporter.stats.get("failed", [])))
print("捕捉用例的跳过对象", len(terminalreporter.stats.get("skipped", [])))
passed_list = list()
_list = []
_list1 = []
passed_object = terminalreporter.stats.get("passed", [])
print("捕捉用例总数", terminalreporter._numcollected)
print("捕捉所有对象", terminalreporter.stats)
for i in passed_object:
print("获取成功用例集对象i:", i)
item2 = str(i).split("::")[0]
if 'test_product/credit' in item2:
_list.append(item2)
if 'test_product/tax' in item2:
_list1.append(item2)
# _list.append(str(i).split("::")[0])
print("获取成功用例集对象名称location", i.location)
passed_list.append(i.location[0])
print(_list)
print(_list1)
print(len(_list))
print(len(_list1))
print(passed_list)
返回情况:
三、pytest结合allure生成测试报告
3.1、用例执行情况查看:
可以结合生成的报告文件-data下的suites.json中获取执行详情进行解析后即可获得,也可以知道每个测试用例集下的情况
四、统计个人名下的测试用例方法:
4.1、添加用例别名并注明作者:
例如:
@pytest.mark.parametrize(
'case_id, case_name,[(test01,test02)], ids=[‘测试testcase1@张三’])
备注:这样该条用例就会统计到作者为-张三名下
4.2、钩子函数统计用例到个人:
def pytest_collection_modifyitems(items):
list_name = []
list_node = []
case_number_list = []
cases_number_dict = {
}
for item in items:
item.name = item.name.encode("utf-8").decode("unicode_escape")
item._nodeid = item.nodeid.encode("utf-8").decode("unicode_escape")
list_node.append(item._nodeid)
list_name.append(item.name)
try:
# 以@开头匹配第一个不是中文的字符串匹配作者
match_obj = re.findall("(?<=@).*?(?=[\x00-\xff])", str(item.name))
case_number_list += match_obj
except:
continue
_list = set(case_number_list)
for i in _list:
cases_number_dict[f'{
i}'] = case_number_list.count(i)
# print(f"=================={case_number_list}")
print(f"=======个人名下用例汇总:{
cases_number_dict}")
logger.info(f"测试用例名称:{
list_name}")
logger.info(f"测试用例文件路径:{
list_node}")
这样就能根据别名中的用例作者去分别匹配用例个数了,最终结果:{‘张三’:1},{‘作者’:用例个数}
五、pytest.fixture实现动态传参的几种方式:
5.1、用法描述:
#coding=utf-8
import pytest
#fixture传单个参数
@pytest.fixture()
def login(request):
name=request.param #request.param就代表参数化的data里的每一个参数
#print("账号是:{}".format(name))
return name
data=["vince","jerry"]
@pytest.mark.parametrize(
'login',
data,
indirect=True
)
def test_01(login):
print("测试账号是:{}".format(login))
if __name__ == '__main__':
pytest.main(["-s","test_param2.py"])
"""
注:
为了提高复用性,我们在写测试用例的时候,会用到不同的fixture,
比如:最常见的登录操作,大部分的用例的前置条件都是登录
假设不同的用例想登录不同的测试账号,
那么登录fixture就不能把账号写死,
需要通过传参的方式来完成登录操作
indirect=True 表示将参数'login'当做一个函数去执行(即参数名要和定义的fixture的函数名一致),而不是一个参数变量,并且将data当做参数传递给该函数
def test_01(login) ,这里的login是获取fixture返回的值
结果:
test_param2.py 测试账号是:vince
.测试账号是:jerry
.
"""
5.2、fixture传多个参数:
#coding=utf-8
import pytest
@pytest.fixture()
def logins(request):
param=request.param
#print("账号是:{}".format(name))
return param
data=[{
"username":"user1","pd":"123"},
{
"username":"user2","pd":"456"}
]
@pytest.mark.parametrize(
'logins',
data,
indirect=True
)
def test_01(logins):
print("测试用户名是:{0}———测试密码是:{1}".format(logins["username"],logins["pwd"]))
if __name__ == '__main__':
pytest.main(["-s","test_param3.py"])
"""
结果:
test_param3.py 测试用户名是:user1———测试密码是:123
.测试用户名是:user2———测试密码是:456
.
"""
5.3、多个fixture叠加装饰器:
#coding=utf-8
import pytest
@pytest.fixture()
def input_user(request):
user=request.param
return user
@pytest.fixture()
def input_pwd(request):
pwd=request.param
return pwd
data=[("user1","123"),
("user2","456")
]
@pytest.mark.parametrize('input_user',data,indirect=True)
@pytest.mark.parametrize('input_pwd',data,indirect=True)
def test_01(input_user,input_pwd):
print("测试用户名是:{0}———测试密码是:{1}".format(input_user,input_pwd))
if __name__ == '__main__':
pytest.main(["-s","test_param5.py"])
"""
结果:
test_param5.py 测试用户名是:('user1', '123')———测试密码是:('user1', '123')
.测试用户名是:('user2', '456')———测试密码是:('user1', '123')
.测试用户名是:('user1', '123')———测试密码是:('user2', '456')
.测试用户名是:('user2', '456')———测试密码是:('user2', '456')
.
"""
使用pytest.fixture()实行动态传参
先在conftest.py文件内创建pytest.fixture()装饰器,定义的函数中需要传参request
获取参数方式为:request.param
@pytest.fixture(scope='function', autouse=False)
def tax_prompt(request):
cert_state = request.param['cert_state']
prompt_error_msg = request.param['prompt_error_msg']
rv = kelp_tax()
rv.common_prompt(cert_state=cert_state, prompt_error_msg=prompt_error_msg)
传递参数方式:
@pytest.mark.parametrize(‘tax_prompt’, [
{‘cert_state’: kelp_tax().prompt_data(num=1)[0][1], ‘prompt_error_msg’: kelp_tax().prompt_data(num=1)[0][0]}],
indirect=True)
Python的switch case写法:
@staticmethod
def prompt_data(num):
numbers = {
0: [("testceshi", "46", "46-testceshi@test")],
1: [("testceshi1", "41", "41-testceshi1@test")],
2: [("testceshi2", "42", "42-testceshi2@test")],,
3: [("testceshi3", "43", "43-testceshi@test")],,
4: "",
5: "",
6: ""
}
return numbers.get(num, None)
一般情况下需要跟测试用例添加别名的方式:
@pytest.mark.parametrize(‘case_name’, [(‘test01’)], ids=[‘test01@test’])