如何在pytest测试场景下自定义Allure报告图片并标注点击位置?
问题解答
1. pytest执行过程中点击位置的记录方案,以及allure.dynamic.label的适用性
allure.dynamic.label不适合用来记录点击坐标这类信息。这个方法的作用是给测试用例打全局元数据标签,比如标注用例所属模块、优先级、负责人这类静态分类属性,数据存在用例的顶层属性位,既没法和单次操作的时序绑定,也不能关联到失败时刻的上下文,完全不匹配操作坐标的记录需求。
可落地的记录方式如下:
- 基于pytest fixture做用例级的操作上下文缓存。写一个function级别的fixture,每个用例执行时初始化一个空列表存储点击记录;把你业务里封装的点击方法(适配Selenium/Appium/Playwright都可以)和这个fixture绑定,每次执行点击前先算好实际点击的坐标(一般取元素中心点),和元素描述、操作时间戳一起存入列表。
- 操作和Allure步骤绑定。用
allure.step装饰每次点击操作,步骤描述里可以直接带上当前点击的坐标信息,方便在报告的步骤流里对应查看。 - 失败时做上下文关联。通过
pytest_runtest_makereport钩子监听用例执行结果,当捕获到用例失败/报错时,拉取当前用例fixture里存的全量点击记录,和当前截取的屏幕快照做绑定,供后续标记使用。
核心逻辑参考代码:
# conftest.py 中实现点击记录fixture import pytest @pytest.fixture(scope="function") def click_tracker(): click_records = [] def track(x, y, element_desc=""): click_records.append({"x": x, "y": y, "desc": element_desc}) yield track, click_records click_records.clear() # 自定义点击方法示例 def perform_click(element, click_tracker): track_func, records = click_tracker # 计算元素中心点作为实际点击坐标 loc = element.location size = element.size click_x = loc["x"] + size["width"] // 2 click_y = loc["y"] + size["height"] // 2 # 先记录再执行点击 track_func(click_x, click_y, str(element)) element.click()
2. Allure报告中截图添加点击标记的实现方案
不要等Allure报告生成完成后再去修改嵌入的截图——Allure生成报告时会把所有附件打包成静态资源,后期改静态文件不仅要找对附件的存储路径,还容易破坏报告的索引结构,维护成本极高。
正确的实现逻辑是:在把截图附加到Allure之前,就完成点位标记的绘制,直接上传处理好的带标记截图。
具体实现步骤:
- 用例失败触发截图时,先把原始截图保存到本地临时目录,不要直接调用
allure.attach上传。 - 从当前用例的
click_tracker缓存里取出需要标记的点击坐标(一般标记失败前最后1-3次点击即可,避免标记太多看不清),用Pillow库打开原始截图,在对应坐标位置绘制圆形标记,可搭配序号、操作说明文字提升可读性。 - 标记绘制完成后,再调用
allure.attach把处理后的截图附加到失败用例的报告内容中,需要留存原始截图的话也可以把原图单独附加,命名区分即可。
绘制标记的参考代码:
from PIL import Image, ImageDraw def add_click_marks(raw_img_path, click_points, output_img_path): """ raw_img_path: 原始截图本地路径 click_points: 待标记坐标列表,格式为[(x坐标, y坐标, 操作描述), ...] output_img_path: 标记后截图的保存路径 """ img = Image.open(raw_img_path) draw = ImageDraw.Draw(img) mark_radius = 10 # 红色描边做标记点,黄色字写标注 mark_outline = (255, 0, 0) text_color = (255, 255, 0) for idx, (x, y, desc) in enumerate(click_points, 1): # 画圆形标记圈 draw.ellipse( (x - mark_radius, y - mark_radius, x + mark_radius, y + mark_radius), outline=mark_outline, width=3 ) # 标注点击序号和说明 draw.text( (x + mark_radius + 3, y - mark_radius), f"点击{idx}: {desc}", fill=text_color ) img.save(output_img_path)
注意:移动端测试场景下要提前做坐标换算,对齐截图分辨率和点击事件的坐标系——比如部分设备要扣除状态栏高度、部分框架返回的坐标是逻辑分辨率而非物理分辨率,提前换算完再画标记,避免点位偏移。
内容的提问来源于stack exchange,提问作者stcnchenxin
相关产品推荐
相关产品推荐

