自动化测试发现问题关联Jira包问题单并上传日志文件和截图
2026/5/16 20:42:03 网站建设 项目流程

一、完整代码实现(基于 Jira REST API + Pytest 钩子)

将以下代码完整放入项目根目录下的conftest.py文件中,即可实现:用例失败后自动创建Jira缺陷工单 → 自动上传失败截图 → 自动上传日志文件 → 自动添加详细评论。

importosimportjsonimportbase64importrequestsfromdatetimeimportdatetimefromrequests.authimportHTTPBasicAuthfrom_pytest.runnerimportpytest_runtest_makereport# ========== 配置区 ==========JIRA_URL="https://your-domain.atlassian.net"# 替换为你的Jira地址JIRA_EMAIL="your-email@example.com"# 替换为你的Jira邮箱JIRA_API_TOKEN="your-api-token"# 替换为你的API TokenJIRA_PROJECT_KEY="PROJ"# 替换为你的项目Key# 截图目录配置(可根据你的测试框架调整)SCREENSHOT_DIR="screenshots"# 截图存放目录LOG_DIR="logs"# 日志存放目录# 优先级映射PRIORITY_MAP={"Critical":"1",# 最高"High":"2","Medium":"3","Low":"4"}defget_jira_auth():"""获取Jira认证对象"""returnHTTPBasicAuth(JIRA_EMAIL,JIRA_API_TOKEN)defcreate_jira_issue(summary:str,description:str,severity:str="High",priority:str="High",test_name:str="",error_message:str="",nodeid:str="")->str:""" 在Jira中创建缺陷工单 参数说明: summary: 缺陷标题 description: 缺陷描述(详细内容) severity: 严重程度(Critical/High/Medium/Low) priority: 优先级(Critical/High/Medium/Low) test_name: 测试用例名称(用于生成更精细的描述) error_message: 错误信息(用于生成更精细的描述) nodeid: 测试用例路径标识(用于生成更精细的描述) 返回:创建的Jira工单Key(如PROJ-123),失败返回None """url=f"{JIRA_URL}/rest/api/3/issue"# 优先级ID映射priority_id_map={"Critical":"1","High":"2","Medium":"3","Low":"4"}# 严重程度映射到Jira自定义字段值severity_map={"Critical":"Blocker","High":"Critical","Medium":"Major","Low":"Minor"}# 构建详细的描述内容full_description=f""" *🤖 自动化测试自动发现的缺陷* **测试用例**:{test_name}**用例路径**:{nodeid}**失败原因**:{error_message}**详细信息**:{description}--- *发现时间*:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*执行环境*:{os.environ.get('ENV','unknown')}*构建链接*:{os.environ.get('BUILD_URL','本地执行,日志未归档')}"""payload={"fields":{"project":{"key":JIRA_PROJECT_KEY},"summary":f"[AutoTest]{summary}","description":full_description,"issuetype":{"name":"Bug"},"priority":{"id":priority_id_map.get(priority,"3")},"customfield_10001":severity_map.get(severity,"Major")}}headers={"Accept":"application/json","Content-Type":"application/json"}auth=get_jira_auth()try:response=requests.post(url,data=json.dumps(payload),headers=headers,auth=auth)ifresponse.status_code==201:issue_key=response.json()["key"]print(f"✅ Jira工单创建成功:{issue_key}")returnissue_keyelse:print(f"❌ Jira工单创建失败:{response.status_code},{response.text}")returnNoneexceptExceptionase:print(f"❌ 创建工单时发生异常:{e}")returnNonedefattach_file_to_jira_issue(issue_key:str,file_path:str)->bool:""" 将文件上传为Jira工单的附件 参数: issue_key: Jira工单Key(如PROJ-123) file_path: 本地文件路径 返回:上传成功返回True,失败返回False """ifnotos.path.exists(file_path):print(f"⚠️ 附件不存在,跳过上传:{file_path}")returnFalseurl=f"{JIRA_URL}/rest/api/3/issue/{issue_key}/attachments"auth=get_jira_auth()headers={"X-Atlassian-Token":"no-check"}# 推断文件MIME类型filename=os.path.basename(file_path)iffilename.endswith(".png"):mime_type="image/png"eliffilename.endswith(".jpg")orfilename.endswith(".jpeg"):mime_type="image/jpeg"eliffilename.endswith(".log")orfilename.endswith(".txt"):mime_type="text/plain"else:mime_type="application/octet-stream"try:withopen(file_path,"rb")asf:files={"file":(filename,f,mime_type)}response=requests.post(url,headers=headers,files=files,auth=auth)ifresponse.status_code==200:print(f"✅ 附件上传成功:{file_path}")returnTrueelse:print(f"❌ 附件上传失败:{response.status_code},{response.text}")returnFalseexceptExceptionase:print(f"❌ 上传附件时发生异常:{e}")returnFalsedefadd_comment_to_jira_issue(issue_key:str,comment_text:str)->bool:""" 在Jira工单中添加评论 参数: issue_key: Jira工单Key comment_text: 评论内容 返回:添加成功返回True,失败返回False """url=f"{JIRA_URL}/rest/api/3/issue/{issue_key}/comment"auth=get_jira_auth()payload={"body":{"type":"doc","version":1,"content":[{"type":"paragraph","content":[{"type":"text","text":comment_text}]}]}}headers={"Accept":"application/json","Content-Type":"application/json"}try:response=requests.post(url,data=json.dumps(payload),headers=headers,auth=auth)ifresponse.status_code==201:print(f"✅ 评论添加成功:{issue_key}")returnTrueelse:print(f"❌ 评论添加失败:{response.status_code},{response.text}")returnFalseexceptExceptionase:print(f"❌ 添加评论时发生异常:{e}")returnFalsedefupload_screenshots_for_issue(issue_key:str,screenshot_paths:list)->int:""" 批量上传截图到Jira工单 参数: issue_key: Jira工单Key screenshot_paths: 截图文件路径列表 返回:成功上传的文件数量 """ifnotscreenshot_paths:return0success_count=0forpathinscreenshot_paths:ifattach_file_to_jira_issue(issue_key,path):success_count+=1ifsuccess_count>0:add_comment_to_jira_issue(issue_key,f"📸 本次失败自动上传了{success_count}张截图,请查看附件。")returnsuccess_countdeffind_latest_screenshot(test_name:str)->str:""" 根据测试用例名称查找最近的失败截图 可根据实际截图策略(如pytest-selenium自动截图)调整此函数 """ifnotos.path.exists(SCREENSHOT_DIR):returnNone# 按修改时间排序查找匹配的截图screenshots=[]forfinos.listdir(SCREENSHOT_DIR):iff.endswith(('.png','.jpg','.jpeg'))andtest_nameinf:f_path=os.path.join(SCREENSHOT_DIR,f)screenshots.append((f_path,os.path.getmtime(f_path)))ifscreenshots:screenshots.sort(key=lambdax:x[1],reverse=True)returnscreenshots[0][0]returnNonedeffind_latest_log(test_name:str)->str:""" 根据测试用例名称查找最近的日志文件 """ifnotos.path.exists(LOG_DIR):returnNonelogs=[]forfinos.listdir(LOG_DIR):iff.endswith(('.log','.txt'))andtest_nameinf:f_path=os.path.join(LOG_DIR,f)logs.append((f_path,os.path.getmtime(f_path)))iflogs:logs.sort(key=lambdax:x[1],reverse=True)returnlogs[0][0]returnNone# ========== Pytest钩子函数 ==========defpytest_runtest_makereport(item,call):""" Pytest钩子函数:在测试用例执行完成后自动调用 这是整个自动提单功能的核心入口 """# 仅在测试用例执行完成后处理(call.when == "call")ifcall.when!="call":return# 获取测试报告对象report=getattr(item,"_rep_call",None)ifreportisNone:return# 仅处理失败的用例ifreport.failed:test_name=item.name nodeid=item.nodeid# 获取错误信息error_message=""ifcall.excinfo:error_message=str(call.excinfo.value)# 查找截图和日志screenshot_path=find_latest_screenshot(test_name)log_path=find_latest_log(test_name)# 构建详细的描述内容description=f"""**执行上下文**:-测试文件:{nodeid}-错误类型:{type(call.excinfo.value).__name__ifcall.excinfoelse'Unknown'}-详细错误栈:

{error_message}

""" # 创建Jira缺陷 issue_key = create_jira_issue( summary=f"[自动化测试失败] {test_name}", description=description, severity="High", # 可根据失败类型动态判断 priority="High", test_name=test_name, error_message=error_message, nodeid=nodeid ) if issue_key: # 上传截图 if screenshot_path: attach_file_to_jira_issue(issue_key, screenshot_path) print(f"📸 截图已上传: {screenshot_path}") # 上传日志 if log_path: attach_file_to_jira_issue(issue_key, log_path) print(f"📄 日志已上传: {log_path}") # 添加上传完成总结 files_uploaded = [] if screenshot_path: files_uploaded.append("截图") if log_path: files_uploaded.append("日志") if files_uploaded: add_comment_to_jira_issue( issue_key, f"✅ 附件上传完成:{', '.join(files_uploaded)} 已自动关联至本工单。\n\n" f"🔗 请开发同学优先处理此自动化发现的问题。" ) print(f"🎉 完整提单流程完成!工单链接: {JIRA_URL}/browse/{issue_key}") else: print("⚠️ 工单创建失败,请检查Jira配置和网络连接")

关键函数说明

函数名作用
create_jira_issue调用Jira REST API创建缺陷工单,返回工单Key
attach_file_to_jira_issue将本地文件(截图/日志)上传为工单附件
add_comment_to_jira_issue在工单中添加文本评论
pytest_runtest_makereportPytest钩子函数,在用例执行完成后自动触发以上流程
find_latest_screenshot/log根据用例名称匹配最近的失败截图和日志(可根据实际框架调整)

配置准备

  1. 获取Jira API Token:登录Atlassian账号 → 进入 https://id.atlassian.com/manage-profile/security/api-tokens → 创建API Token并保存
  2. 修改配置区参数
    • JIRA_URL:替换为你的Jira地址(如https://your-domain.atlassian.net
    • JIRA_EMAIL:你的Jira登录邮箱
    • JIRA_API_TOKEN:上一步获取的Token
    • JIRA_PROJECT_KEY:目标项目的Key(如PROJTEST
  3. 确认自定义字段:代码中的customfield_10001是Jira Cloud中“严重程度”字段的默认ID。如果该字段在你的实例中ID不同(Cloud版本通常为10001,Data Center/Server版本可能不同),请通过curl或Jira界面获取正确的自定义字段ID后修改。

二、Trae操作步骤

步骤一:环境准备

  1. 从 https://www.trae.cn/ 下载并安装Trae IDE
  2. 在Trae中新建项目,选择Python项目模板
  3. 确保项目目录中包含你的测试用例(通常位于tests/目录下)

步骤二:通过Trae生成Jira集成代码

方式A:IDE模式(适合专业测试工程师)

在Trae IDE中,按Ctrl+I(或Cmd+I)唤起AI助手,输入以下自然语言指令:

请帮我生成pytest + Jira集成代码,放在conftest.py文件中,要求: 1. 实现pytest_runtest_makereport钩子函数,在测试失败时自动触发 2. 调用Jira REST API创建缺陷工单(包含:项目Key、优先级、严重程度) 3. 自动将失败截图和日志文件上传为Jira工单附件 4. 在工单中添加自动化测试结果和详细日志的评论 5. 支持通过环境变量或配置文件管理Jira认证信息 6. 完整输出可直接运行的Python代码,包含必要的异常处理

Trae会在AI助手面板中直接生成完整代码。将生成的代码复制到项目根目录的conftest.py中即可。

方式B:SOLO模式(适合快速原型验证)

Trae的SOLO模式支持自然语言输入开发需求,AI自动完成从需求理解到代码生成的全流程。

  1. 打开Trae,选择SOLO模式进入
  2. 在自然语言交互界面中输入:
请帮我构建一个自动化测试Jira集成项目,要求如下: - 使用pytest框架 - 测试失败时自动向Jira提交缺陷工单 - 需要上传失败截图和日志文件 - Jira认证信息通过配置文件管理 - 输出完整的conftest.py代码
  1. 提交需求后,Trae SOLO会自动完成项目分析和代码生成
  2. 将生成的代码复制到项目中使用

步骤三:配置Jira认证

创建项目根目录下的.env文件:

JIRA_URL=https://your-domain.atlassian.netJIRA_EMAIL=your-email@example.comJIRA_API_TOKEN=your-api-tokenJIRA_PROJECT_KEY=PROJ

在Trae中修改conftest.py配置区,或在代码中添加从环境变量读取的逻辑。

步骤四:截图和日志路径适配

根据你的实际测试框架调整find_latest_screenshotfind_latest_log函数:

场景1:使用pytest-selenium自动截图

defpytest_runtest_makereport(item,call):ifcall.when=="call"andcall.excinfoisnotNone:driver=item.funcargs.get('driver')# 假设你有一个driver fixturescreenshot_path=f"screenshots/{item.name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"driver.save_screenshot(screenshot_path)# 然后调用创建Jira工单的函数...

场景2:使用pytest-playwright自动截图

fromplaywright.sync_apiimportPagedefpytest_runtest_makereport(item,call):ifcall.when=="call"andcall.excinfoisnotNone:page=item.funcargs.get('page')screenshot_path=f"screenshots/{item.name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"page.screenshot(path=screenshot_path)

场景3:没有截图机制,需要从零添加

在Trae中输入指令让AI帮你添加截图功能:

请帮我修改conftest.py,在测试失败时自动捕获浏览器截图。 我使用的是[Playwright / Selenium],截图保存到screenshots目录下。

步骤五:验证与集成

  1. 运行一次测试(可故意写一个失败的用例):
    pytest tests/test_example.py-v
  2. 观察控制台输出,确认看到✅ Jira工单创建成功: PROJ-123字样
  3. 登录Jira,确认工单已创建、附件已上传、评论已添加

步骤六:CI/CD集成

将上述配置提交到Git仓库后,在CI流水线(Jenkins/GitLab CI/GitHub Actions)中配置以下环境变量:

# GitHub Actions示例-name:Run tests with Jira integrationenv:JIRA_URL:${{secrets.JIRA_URL}}JIRA_EMAIL:${{secrets.JIRA_EMAIL}}JIRA_API_TOKEN:${{secrets.JIRA_API_TOKEN}}JIRA_PROJECT_KEY:${{secrets.JIRA_PROJECT_KEY}}BUILD_URL:${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}run:|pip install -r requirements.txt pytest tests/ --junitxml=test-results.xml

常见问题排查

问题排查方法
认证失败(401/403)检查API Token是否有效,邮箱是否为Jira登录邮箱
附件上传失败(500)检查文件大小是否超过Jira限制(默认10MB),文件名是否包含特殊字符
自定义字段ID不正确通过curl -u email:token "你的Jira地址/rest/api/3/field"查看字段列表
找不到截图/日志文件检查find_latest_screenshot/log函数中的目录路径是否与实际情况匹配

三、效果示例

测试失败后

  1. ✅ 控制台输出:✅ Jira工单创建成功: TEST-101
  2. ✅ 工单自动关联:标题包含[AutoTest]标识,描述包含用例名、错误堆栈、执行时间、构建链接
  3. ✅ 附件自动上传:失败时的屏幕截图、pytest执行日志
  4. ✅ 评论自动添加:✅ 附件上传完成:截图, 日志 已自动关联至本工单。🔗 请开发同学优先处理此自动化发现的问题。
  5. ✅ 开发人员收到Jira通知,可直接在工单中查看截图定位问题

通过Trae生成此方案的优势

  • 零代码基础的测试工程师也能在10分钟内完成配置
  • Trae的AI上下文感知能力可自动适配项目技术栈(Playwright/Selenium/requests)
  • 支持多智能体协同,可进一步扩展为自动分析缺陷根因、自动分配责任人

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询