ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

测试报告驱动Jira Bug自动关闭:API脚本化状态流转实践

测试报告驱动Jira Bug自动关闭:API脚本化状态流转实践 1. 这个联动要解决的其实是手滑和遗忘的问题先从我自己的团队说起。之前我们每个迭代结束测试这边最烦的并不是执行测试用例而是清场阶段开发把Bug修完测试回归通过然后我要打开Jira挨个把Bug从待验证拖到已关闭再补上一句已验证通过详见测试报告链接。听起来也就十秒钟一个单子可一个迭代几十个Bug加上中途穿插的线上问题每天花在这种机械操作上的时间至少有半小时到一小时。更麻烦的是什么呢是漏和错。漏是指有些Bug明明已经在测试报告里标了PASS但因为验证的时候手头在忙别的等想起来去关单已经是第二天甚至更晚了。错是指关错单——验证的是A环境结果在另一个工单下留了评论或者回归没问题但状态流转的时候选错了关闭原因导致统计口径全部乱掉。后来我们梳理了一下发现这个问题的本质不在测试人员懒而在信息在系统之间流转靠人工手工搬运测试报告是一个系统Jira工单是另一个系统两者之间的桥梁就是人的双手。只要存在人工中转就有延迟、遗漏和输入错误的可能。所以我们的目标很明确让测试报告里的已验证通过这条结果能自动驱动Jira工单做状态流转把关闭Bug这个动作从手动菜单里解放出来。这个项目实际做下来核心工作其实就三件事解析测试报告的结论、定义Jira工单状态机的判定规则、以及用脚本把两者串起来跑。下面我把我踩过的坑和最终落地的方案都写出来希望能帮到正被这类重复劳动困扰的团队。2. 技术方案选型为什么不只依赖Jira插件而是选择脚本化调API做之前我们其实先调研了一圈现成的方案。Jira本身有Automation插件能配置当某个字段变化时自动执行状态流转理论上也能做到自动关闭。它的优势是零代码、界面化团队里如果全是Jira重度用户用Automation做简单的字段触发确实挺方便。但我们的场景有点特殊。我们的测试报告并不存在Jira里而是存在内部的测试管理平台和CI的产物里。每次回归测试跑完报告是一个独立的HTML/JSON文件里面记录了测试用例和关联的Jira Bug ID。也就是说Bug修复了这个事实最先出现在测试报告里而不是Jira的任何字段里。Automation插件如果要用也得先想办法把报告结果同步进Jira自定义字段这一层同步反而更麻烦。最终我们选择了脚本化调用Jira REST API的方式用Python写一个独立的小服务定期或由CI触发执行。选这个方案有几个现实考量测试报告已经是JSON格式直接解析即可不需要二次加工。Jira的REST API足够成熟批量查询、状态流转、添加评论、上传附件都能做。脚本可以很方便地记录审计日志每次自动关单的操作都能追溯到哪个报告、哪个用例、什么时间触发的关闭这对QA来说很重要不然出了问题说不清楚。后续如果想把测试通过且Bug关闭的数据回推给项目看板做质量报表脚本里直接加个逻辑就行。当然我们不排除Automation在某些团队里能用得更好。但如果你也面临报告和Jira是两套系统、且报告这边是关键输入的情况API脚本化基本是绕不开的最优解因为它把规则完全掌握在自己手里不依赖Jira内置触发器的灵活性。3. 状态机与判定规则什么样的Bug才允许被自动关闭这个项目里最容易翻车的地方不是写代码而是定义可以自动关闭的规则。如果规则定得太松会把还没真正验证完的Bug误关掉定得太死自动化的价值又体现不出来。我们最终把自动关闭的判定规则拆成了五层每一层都有明确的目的缺一不可。3.1 第一层报告侧必须有明确的已通过证据这个听起来是废话但做的时候会发现报告本身就很混乱。我们的测试管理平台每个用例执行结果可能有好几个字段执行状态、结论、备注、关联Bug。一开始我们只按执行状态PASS来判定结果发现有的用例虽然PASS了但测试人员备注里写着仅验证部分场景剩余场景下轮覆盖。这种就不应该触发自动关闭。所以我们加了硬性要求触发自动关闭的用例必须满足执行状态PASS 且 结论字段通过 且 无部分通过标记。这个规则直接在解析报告时就过滤掉不会让脏数据进到Jira侧。3.2 第二层Jira工单当前状态必须处于待验证或已修复自动关闭的本质是状态机的流转如果工单当前状态是新建或者进行中说明开发还没提交修复测试报告里却标了PASS那大概率是报告数据关联错了。我们要求脚本在调用关闭接口前必须先获取工单当前状态只允许以下两种状态被自动关闭待验证开发已提交修复测试正在回归中报告PASS后可以流转到关闭。已修复部分团队会用已修复表示开发认为修好了还没进入测试环节这时候报告里PASS也说明验证完成可以关。除了这两个状态其他一律跳过并记入异常日志绝不强关。3.3 第三层关闭原因和解决版本必须匹配Jira在关闭Bug时通常会要求填写关闭原因和解决版本。原本手动操作时测试人员随手选的很多导致后来统计哪些Bug是在哪个版本修掉的时经常对不上账。自动关闭时我们固定了两条规则关闭原因 Fixed如果是通过测试验证关闭的固定走已修复这个语义。解决版本 测试报告里标明的验证版本号如果报告里没有版本号则取当前迭代默认的Fixed Version。版本号这个字段特别重要因为很多QA团队的实际痛点是Bug本身关闭了但财务或项目管理侧想知道它是在哪个版本修复的如果关闭时版本字段是空的这个Bug就等于无主资产。所以我们的脚本里强制要求无法获取解决版本时宁可跳过也不自动关。3.4 第四层幂等性保护做自动化最怕的就是重复执行导致状态错乱。比如脚本因为网络超时同一个报告被重试了三次如果每次执行都重新走一遍查询→判断→关闭第一次能关掉第二三次会报状态不允许流转虽然不会重复关单但会产生大量错误日志。我们的做法是脚本执行前先查该工单的变更历史如果历史里存在由自动关闭脚本触发的关闭操作且时间是在本次执行周期内就直接跳过。另外我们给每条测试报告用例 Bug ID组合生成了一个全局唯一的执行Key每次执行结果都记录到本地的SQLite里重复执行只更新状态不重复触发Jira操作。3.5 第五层人工兜底无论规则多严谨总会遇到边缘场景。所以我们设计了一个自动关闭只做有把握的事原则凡是触发条件不满足的Bug脚本不会尝试关闭而是统一汇总到一条每日邮件里由测试负责人人工review。这样自动化负责处理90%的常规Case人工只处理10%的异常Case整体效率反而最高。4. 核心实现从测试报告解析到Jira自动关闭的完整链路下面进入到实际编码环节。我们最终跑通的流程是这样的CI触发回归测试 - 生成报告(JSON) - Python脚本解析报告 - 筛选PASS且带BugID的用例 - 查询Jira工单状态 - 校验规则 - 添加评论附件 - 状态流转为关闭 - 记录审计日志接下来是每个环节的关键代码和配置我尽量把可直接用的部分贴出来。我们用的Jira是Server版云版API地址稍有差异但基本逻辑一致。4.1 测试报告的结构假设我们的测试管理平台导出的JSON长这样{ report_id: REPORT-20250321-001, project: APP, test_version: 3.2.0, cases: [ { case_id: TC-1001, case_title: 验证登录失败提示, execution_status: PASS, conclusion: 通过, linked_bugs: [BUG-101, BUG-102] }, { case_id: TC-1002, case_title: 验证支付回调, execution_status: FAIL, conclusion: 失败, linked_bugs: [BUG-103] } ] }如果你的报告是JUnit XML或者Allure生成的核心思路也一样只要能识别出用例通过 关联Bug ID 验证版本这三个信息就行。4.2 Jira相关配置和认证Jira的认证推荐用API Token不要用账号密码。我们用的是Basic Auth Tokenimport requests from requests.auth import HTTPBasicAuth JIRA_URL https://your-jira.example.com JIRA_USER automation-user JIRA_TOKEN xxxxxxxxxxxxxxxxxxxx AUTH HTTPBasicAuth(JIRA_USER, JIRA_TOKEN) HEADERS {Accept: application/json, Content-Type: application/json}有个细节要注意自动化账号的权限必须包含浏览工单编辑工单执行状态流转添加评论上传附件这几项而且这个账号不能是某个离职员工的个人账号。我们吃过亏最初用了一个QA个人账号当机器人结果这人休假的时候关联的鉴权Token带着基本权限不完整脚本跑一半就报权限错。建议单独建一个自动化服务账号并且在Jira里不允许它修改经办人字段防止脚本意外改动工单所有权。4.3 查询工单当前状态调用的API路径是GET /rest/api/2/issue/{issue_key}我们只关心状态和解决版本所以用fields参数过滤def get_jira_issue(issue_key): url f{JIRA_URL}/rest/api/2/issue/{issue_key} params {fields: status,resolution,fixVersions,project} resp requests.get(url, paramsparams, authAUTH, headersHEADERS, timeout10) resp.raise_for_status() return resp.json() # 返回示例 # { # fields: { # status: {name: 待验证}, # resolution: null, # fixVersions: [{name: 3.2.0}] # } # }这里我用了一个小技巧把允许自动关闭的状态列表放进一个配置文件而不是硬编码在代码里。因为Jira工作流在各项目里经常微调硬编码状态名的话下个项目可能就对不上了。后续可以通过一个简单的mapping配置两分钟就能适配新项目。4.4 自动执行状态流转Jira的API里状态流转是通过transitions来实现的。先要获取当前工单有哪些可用流转GET /rest/api/2/issue/{issue_key}/transitions然后找到目标关闭状态的transition id执行def close_issue(issue_key, comment_text): url f{JIRA_URL}/rest/api/2/issue/{issue_key}/transitions # 因为不同项目状态名不同我们统一用关闭作为目标状态名去匹配 transitions_resp requests.get(url, authAUTH, headersHEADERS, timeout10).json() target_transition None for t in transitions_resp.get(transitions, []): if 关闭 in t[to][name]: target_transition t[id] break if not target_transition: raise Exception(f工单 {issue_key} 没有可用的关闭流转) payload { transition: {id: target_transition}, update: { comment: [{add: {body: comment_text}}] } } resp requests.post(url, jsonpayload, authAUTH, headersHEADERS, timeout10) resp.raise_for_status() return resp.status_code这里有个重要的经验不要直接在POST里写死transition id因为不同项目、不同工作流的transition id完全不一样。一定要先查询再匹配否则脚本换个项目就崩。另外如果你需要设置解决版本不能通过transitions接口直接传得用PUT /rest/api/2/issue/{issue_key}单独更新字段。所以我们实际执行时是两步先更新fixVersions再执行流转。4.5 评论与附件的处理自动关闭时我们会在工单里留一条评论内容结构是【自动关闭】该Bug已由自动化回归测试验证通过关联测试报告REPORT-20250321-001用例TC-1001验证版本3.2.0。 本操作为脚本自动执行如有问题请联系测试负责人。这段评论非常重要。我们经历过一次自动化误关事后排查时如果没有这条评论根本不知道这个Bug是被脚本关掉的。而且这条评论的格式还能直接被后续的报表系统解析用来统计自动关闭占比。上传附件的话Jira API支持multipart文件上传def attach_file_to_issue(issue_key, file_path): url f{JIRA_URL}/rest/api/2/issue/{issue_key}/attachments with open(file_path, rb) as f: files {file: (file_path.name, f, application/octet-stream)} headers {X-Atlassian-Token: no-check} resp requests.post(url, filesfiles, authAUTH, headersheaders, timeout30) resp.raise_for_status()但这里要注意附件大小限制和Jira实例配置有关如果测试报告特别大直接传附件容易失败。我们实际做法是只传一个精简版的执行结果截图或摘要PDF完整报告留在测试管理平台通过评论里的链接跳转。这样既保留了证据又不会让Jira的附件空间爆掉。4.6 调度与执行我们最终把这个脚本部署在一台内网的通用跳板机上用crontab每30分钟跑一次同时支持CI流水线在回归测试完成后立即触发一次。因为脚本是幂等的即使两条路径同时触发也不会重复关单。crontab示例*/30 * * * * cd /opt/bug-auto-close /usr/bin/python3 main.py logs/execution.log 21如果你跑在Jenkins/GitLab CI里只需要把每一步做成可执行单元最后汇总成功/失败/跳过数量即可。5. 踩坑实录权限、幂等性、误关与重复执行的边界问题任何自动化项目都有坑这个项目尤其多。我把我们实际踩过的、以及社区里大家经常遇到的问题整理成了一份排查列表希望能帮你少走弯路。5.1 权限不足导致的状态流转失败这是上线第一周碰到的最常见问题。现象是查询工单正常但执行流转时报403。查了半天发现是自动化账号缺少了工作流流转这个细粒度权限。Jira的权限体系里即使在项目权限里给了编辑工单也不代表你能执行所有状态流转需要额外检查权限方案里是否允许该角色在工作流模块里操作流转工单。解决方案让Jira管理员在项目权限方案里给自动化账号分配Transition Issues权限。如果权限是继承自项目角色的要确认自动化账号被加入了这个角色。5.2 状态名在不同项目之间不一致我们公司有几十个项目每个项目的Jira工作流都是各团队自己配的。A项目的待验证在B项目里可能叫待回归C项目里叫Fix Ready。如果脚本里硬编码状态名换项目就全废。我们的解法是引入一个配置文件把各项目的状态映射写清楚projects: APP: allowed_statuses: [待验证, 已修复] close_transition_keyword: 关闭 API: allowed_statuses: [待回归, 修复完成] close_transition_keyword: Done脚本每次执行前先加载当前项目的配置所有状态判断都用配置来匹配而不是代码里写死。这样换项目只要改配置不用改代码。5.3 自动关闭的误伤关联Bug字段填错了这个是所有坑里影响最大的一个。出现过一次某个测试用例执行结果是PASS但测试人员在执行时把关联Bug字段误填成了另一个还没修好的Bug导致脚本直接把这个Bug关了。事后开发反馈我还没改完呢怎么Bug就关闭了。从这次事故我们总结了一条铁律自动关闭必须限定在该Bug在本次报告对应的迭代版本中有修复记录。也就是说光看测试用例PASS不够还得验证Bug的解决版本和当前报告的验证版本一致。如果不一致说明这个Bug可能是在旧版本修好的本轮报告中PASS并不代表本轮验证通过。我们又加了第三条校验Bug必须曾经被设置为待验证状态超过至少1分钟即开发确实提交过修复否则即使测试用例PASS也不自动关。这个校验能拦掉开发还没提交测试已经把用例标PASS的错误顺序。5.4 重试导致的重复执行问题前面提到过幂等性这里展开说下具体怎么做的。我们用一个SQLite表记录执行结果CREATE TABLE execution_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, report_id TEXT NOT NULL, issue_key TEXT NOT NULL, execution_key TEXT NOT NULL, status TEXT NOT NULL, -- SUCCESS/SKIPPED/FAILED created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(report_id, issue_key) );每次脚本跑完一个用例工单组合就往这个表里插入一条记录。下次执行时先查一下这个组合是否存在存在就直接跳过。这样即使同一个报告被误触发了十次数据库也能保证只有第一次真正对Jira进行操作。另外Jira侧本身也有状态机保护已经被关闭的Bug再次尝试关闭流转时API会报错所以双重保险之下重复关单的概率基本为零。5.5 关闭原因填了但不能保存有些Jira工作流在关闭时会强制要求填resolutions字段。我们第一次用API自动关闭时报了400用Postman手动测也是400后来发现是因为关闭流转时payload里必须带上resolution字段{ transition: {id: xxx}, fields: { resolution: {name: Fixed} } }这个问题不大但很容易忽略因为手动在界面上操作时Jira会自动填充resolution而API调用时必须显式传值否则报错。5.6 附件上传超时回归测试报告有时候会附带很长的执行日志直接作为附件传Jira会超时。我们的处理办法是尝试压缩日志文件只保留ERROR级别和关键警告。超过2MB就只传摘要文件完整日志保留在测试平台。这是一个用户体验和系统稳定性的平衡问题别把一个低频工具搞成Jira性能杀手。6. 上线后的效果与下一步可以怎么玩这个联动系统上线到现在跑了两个迭代实际效果比预期好不少。我直接给一组我们自己的数据仅供参考你们的环境肯定不太一样指标手动操作时自动联动后单个Bug从测试PASS到Jira关闭的平均耗时约4小时因为积压很多是隔天才关1分钟CI触发后立即执行迭代末Bug关闭率83%97%因为状态未及时更新导致的项目报表统计冲突每迭代3-5次0次测试人员在清场阶段的时间投入每人约30分钟/天约5分钟/天只处理异常我觉得这个项目最有价值的不是省了那半小时而是让Bug状态和真实质量状态保持一致。以前看板上的Bug数是假低——因为测试已经验证完了但还没来得及关单看起来这个迭代还没完成现在自动关闭一跑看板数据立刻反映真实进度项目经理和开发经理都不用来回问QA到底修完没有了。下一步我们计划做两件事反向链路如果自动关闭后有回归测试在后续迭代中再次FAIL了同一个用例自动将关联Bug重新打开并置为Reopened状态。质量报表把每次自动关闭的审计信息同步到数据仓库按模块、按开发人员分析Bug修复率和回归通过率。如果你所在团队也被测试报告和Bug管理割裂的重复劳动困扰按我上面这套思路搭一个最小版本其实很快。关键不是代码多复杂而是规则先定义清楚状态机先理明白权限先配到位然后再动手写脚本。流程设计对了代码只是顺手的工具。
返回列表