【Pytest 测试so库时遇到Python Fatal Error 继续执行测试】

Pytest 测试so库时遇到Python Fatal Error 继续执行测试,并生成allure报告

pytest遇到Segmentation后继续运行后续测试

使用pytest-xdist分布式运行, woker节点崩溃后xdist会重新启动新进程进行测试, 并向自己的Terminal 里报告fail。但是这条fail, Allure 报告抓取不到。

Allure报告展示crash时case结果为fail

pytest-xdist内置pytest_handle_crashitem钩子函数, 在conftest.py里实现这个钩子函数并进行处理。 因为crash之后后续的hook函数都不会被运行,所有需要在pytest_handle_crashitem钩子函数里主动调用,以生成allure数据
conftest.py

@pytest.hookimp(tryfirst=True)
def pytest_handlecrashitem(crashitem,report, sched):
	allure_listener = report.node.config.pluginmanager.get_plugin("allure-listener")  #获取allure_listener
	allure_listener_hook = allure_listener.config.hook #获取allure_listener的hook
	item = copy.copy(report)
	gen_test_result(allure_listener, item)  #生成allure报告,这样才会有数据写到allure的json文件里
	allure_listener_hook.pytest_runtest_logfinish(nodeid=crashitem, location=report.location) #这个钩子函数会调到allure_listener.allue_logger.close_test(uuid). 最终把结果写入result.json	

gen_test_result()主要用于生成测试报告,否则最终生成的reslut.json文件没有内容
AllureListener 位于site-packages/allure_pytest/listener.py

from allure_common.utils import md5,platform_label
from allure_common.model2 import Label, TestResult
from allure_common.types import LabelType
from allure_pytest.utils import allure_package

def gen_test_result(allure_listener, item):
	uuid=allure_listener._cache.push(item.nodeid)
	crashitmeList = item.nodeid.split("::")
	name = crashitemList[-1]
	test_result = TestResult(name=name, uuid=uuid, start=now(), stop=now())
	allure_listener.allure_logger.schedule_test(uuid, test_result)
	for i in range(len(crashitemList)-1):
		crashitemList[i]=crashitemList[i].replace(os.sep, ".")
	index = name.find("[")
	if index !=-1:
		crashitemList[-1] = crashitemList[-1][:index]
	full_name = "."join(crashitemList[:-1])+"#"+crashitemList[-1]
	test_result.fullName = full_name
	test_result.historyId = md(item.nodeid)
	test_result.testCaseId = md5(full_name)
	test_result.labels.extend([Label(name=name, value=value) for name, value in allure_suite_labels(item)]) #生成suite
	test_result.labels.append(Label(name=LabelType.HOST, value=allure_listener._host) )
	test_result.labels.append(Label(name=LabelType.THREAD, value=allure_listener._thread) )
	test_result.labels.append(Label(name=LabelType.FRAMEWORK, value="pytest") )
	test_result.labels.append(Label(name=LabelType.LANGUAGE, value=platform_label()) )
	test_result.labels.append(Label(name="package", value=allure_package(item)) )
	test_result.status="failed"
	from _pytest.code import getfslineno
	path, lineno = getfslineno(item)
	test_result.statusDetail=StatusDetails(message=info)
	###以下时等待core file生成并把core dump attach到allure报告里
	cmd = r"""ps aux | grep "\[python3\] <defunct>" | awk '{print $2}' """  #获取crash的进程id
	result = subprocess.run(cmd, stdout=subprocess.PIPE, shell=True)
	pid = result.stdout.decode().strip()
	coreFile= f"core.{pid}" # core dump文件命名为core.pid
	q=queue.Queue()
	th = threading.Thread(target=waitQForfile, args=(q, coreFile))
	th.start() 
	try:
		q.get(timeout=60)
	except queue.Empty:
		logging.error("wait core dump failed")
	else:
		allure_listener.allure_logger.attach_file(uuid=uuid, source=coreFile, name="core dump") # attach core dump到allure报告

def allure_suite_labels(item): #重写了site-package/allure_pytest_utils.py#allure_suite_labels
	head, possibly_clazz, tail = isslice(chain(item.nodeid.split('::'), [None],[None]), 3)
	clazz = possibly_clazz if tail else None
	file_name, path = islice(chain(reversed(head.raplit('/',1)), [None]),2)
	module = file_name.split('.')[0]
	package = path.replace('/', '.') if path else None
	pairs = dict(zip([LabelType.PARENT_SUITE, LabelType.SUITE, LabelType.SUB_SUITE], [package,module, clazz]))
	labels = dict() #这里因为获取不到item的label,所以直接赋值空字典
	default_suite_labels = []
	for label, value in pair.items():
		if label not in labels.keys() and value:
			default_suite_labels.append(label,value))
	return default_suite_labels
def waitQForfile(q,file):
	while True:
		if os.path.exists(file):
			q.put("done")
			break
		else:
			tiem.sleep(1)
	
	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值