在研发团队里,有一个古老而令人头秃的问题:开发写完代码,测试不知道测啥;或者测试拿到提测,只能对着模糊的 commit message 发呆。
“修复了一个 bug。” “优化了性能。” “更新了代码。”
看到这种 Git 提交信息,测试同事大概率已经在提刀赶来的路上了。
为了解决这个痛点,很多团队尝试推行“规范化 commit”,比如使用 Angular 规范。但这只是第一步。真正的效率提升,是让开发在写完规范的 commit 后,系统能自动理解意图,生成一份初步的测试规程(Test Procedure),并一键推送给对应的测试同事。
今天我们就来硬核实战:如何利用 GitLab CI/CD、Python、OpenAI API(这里我们用它来做语义解析)和企业微信机器人,打通这条自动化链路。
核心逻辑:从 Commit 到 Test Case
这套流程的核心不在于技术堆砌,而在于语义解析。
传统的方法可能是通过正则匹配 feat: 就生成“请测试新功能”。这太弱智了。我们要的是:
Commit:feat(order): 优化订单查询接口,支持按手机号后四位模糊搜索 #123
自动化期望:
测试场景: 订单查询-模糊搜索
测试步骤: 1. 进入订单查询页面;2. 在手机号输入框输入手机号后四位;3. 点击搜索。
预期结果: 搜索结果列表中包含该手机号对应的订单,且支持模糊匹配。
关联单号: #123
这就需要 AI 的介入了。整个架构如下:
Git Push: 开发提交代码。
GitLab CI: 触发 Pipeline,抓取本次提交的 Commit Message。
解析脚本 (Python): 核心部分。它将 Commit Message 发送给 AI 模型。
AI 模型: 将文本转换成结构化的测试意图。
企业微信机器人: 将结构化的测试规程推送给测试群。
避坑指南:先准备好“原料”
在动手写代码前,请务必准备好以下东西,缺一不可:
企业微信机器人 Webhook URL: 在企业微信群里,右键->添加机器人。你会得到一个形如 https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx-xxxx 的 URL。请像保护银行卡密码一样保护它。
OpenAI 或其它大模型 API Key: 我们需要它的语义理解能力。如果你用国内的模型(如文心一言、通义千问),逻辑是一样的。
GitLab 项目权限: 需要能配置 CI/CD Variables。
Commit Message 规范: 你的团队必须已经在推行规范,至少包含 type(scope): subject 格式。如果是乱写的 commit,AI 也救不了你。
实战步骤
步骤一:配置 GitLab CI/CD 变量
千万不要把任何 API Key 或 Webhook URL 直接写在代码里!这是最基本的安全准则。
进入你的 GitLab 项目 -> Settings -> CI/CD -> Variables。添加以下变量:
QYWECHAT_WEBHOOK_URL: 你的企业微信机器人 Webhook。
OPENAI_API_KEY: 你的 OpenAI API Key。
步骤二:编写解析与发送脚本 (gen_test_procedure.py)
在项目根目录下创建一个 Python 脚本。这个脚本是灵魂。它干了两件事:调用 AI 解析,然后调用企业微信推送。
这里有一个至关重要的技巧:我们不能只把 commit 内容扔给 AI,必须给它一个严谨的 System Prompt (系统提示词),规定它返回固定的 JSON 格式。否则,你得到的回复将是一堆乱七八糟的文本,根本没法被脚本二次处理。
gen_test_procedure.py
import os
import requests
import json
import sys
1. 从环境变量获取敏感信息
QYWECHAT_WEBHOOK = os.getenv('QYWECHAT_WEBHOOK_URL')
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
OPENAI_API_BASE = os.getenv('OPENAI_API_BASE', 'https://api.openai.com/v1') # 支持代理
获取 Git 提交信息(从 CI 环境变量或命令行参数)
commit_msg = os.getenv('CI_COMMIT_MESSAGE') or (sys.argv[1] if len(sys.argv) > 1else"")
commit_author = os.getenv('CI_COMMIT_AUTHOR') or"未知作者"
project_url = os.getenv('CI_PROJECT_URL')
ifnot commit_msg:
print("Error: No commit message found.")
sys.exit(0) # 不要在 CI 中报错退出,避免阻塞流程
def ask_ai_for_test_procedure(msg):
"""
这是核心:通过 System Prompt 强制 AI 返回结构化 JSON
"""
headers = {
"Authorization": f"Bearer {OPENAI_API_KEY}",
"Content-Type": "application/json"
}
# 这是最关键的 Prompt,决定了生成的质量
system_prompt = """
你是专业的软件测试专家。你的任务是将输入的 Git Commit Message 转换为一份简要的测试规程。
必须且只能返回一个符合以下格式的纯 JSON 对象,不要包含任何其它解释文本或 Markdown 标记。
JSON 格式要求:
{
"test_scenario": "测试场景的简要描述",
"steps": ["步骤1", "步骤2", "..."],
"expected_result": "预期结果"
}
如果 Commit Message 内容太少或无法理解,请生成一个最基本的通用测试步骤,例如“确认功能是否受到影响”。
"""
data = {
"model": "gpt-3.5-turbo-1106", # 推荐用 1106 或更新版本,对 JSON 输出支持更好
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"Commit Message: {msg}"}
],
"temperature": 0.3, # 低温度,保证输出的稳定性
"response_format": { "type": "json_object" } # 强制 OpenAI 返回 JSON
}
try:
response = requests.post(f"{OPENAI_API_BASE}/chat/completions", headers=headers, json=data)
response.raise_for_status()
result = response.json()
return json.loads(result['choices'][0]['message']['content'])
except Exception as e:
print(f"Error calling AI: {e}")
returnNone
def send_to_qywechat(test_data, author, orig_msg, url):
"""
将解析好的数据格式化,并推送给企业微信
这里用 Markdown 格式,看起来更整洁
"""
ifnot test_data:
return
# 格式化消息内容
# 开发写的 commit 我们可以原样保留作为参考
orig_msg_truncated = orig_msg.split('\n')[0] # 只拿第一行
markdown_content = f"""## 🚀 收到新功能/修复提测
提交作者: {author}
代码仓库: 点击查看
原始提交: {orig_msg_truncated}
AI 自动生成的测试规程 (仅供参考):
1️⃣ 测试场景
{test_data.get('test_scenario', '未知')}
2️⃣ 测试步骤
"""
# 动态生成步骤列表
steps = test_data.get('steps', [])
for i, step in enumerate(steps):
markdown_content += f"{i+1}. {step}\n"
markdown_content += f"""
3️⃣ 预期结果
{test_data.get('expected_result', '未知')}
@测试同事 请关注。如果您认为 AI 生成的不准确,请手动补充。
"""
wechat_data = {
"msgtype": "markdown",
"markdown": {
"content": markdown_content
}
}
try:
requests.post(QYWECHAT_WEBHOOK, json=wechat_data)
print("Success: Message sent to QyWechat.")
except Exception as e:
print(f"Error sending to QyWechat: {e}")
--- 主流程 ---
print(f"Processing commit: {commit_msg.split('\n')[0]}")
1. 只有 feat 和 fix 类型才生成测试规程(这里是工程权衡)
如果你的规范不一样,请修改这里
is_relevant = commit_msg.startswith('feat') or commit_msg.startswith('fix')
ifnot is_relevant:
print("Skipping: Not a feat or fix commit.")
# 你依然可以选择推送一个简略的通知,告诉大家有人提交代码了
sys.exit(0)
2. 调用 AI
test_procedure = ask_ai_for_test_procedure(commit_msg)
3. 推送
if test_procedure:
send_to_qywechat(test_procedure, commit_author, commit_msg, project_url)
步骤三:配置 GitLab CI (.gitlab-ci.yml)
最后,我们要告诉 GitLab 什么时候运行这个脚本。在 .gitlab-ci.yml 中添加一个 job。
这个 job 的关键在于:它不需要依赖项目的编译环境,只需要一个干净的 Python 环境即可。我们利用 GitLab CI 的环境变量自动抓取 CI_COMMIT_MESSAGE 等信息。
.gitlab-ci.yml
stages:
-build
-test
-notify# 添加一个通知阶段
notify_test_procedure:
stage:notify
image:python:3.9-slim# 使用轻量级 Python 镜像
script:
-pipinstallrequests# 安装脚本依赖
# 运行脚本。脚本内部会读取 CI_COMMIT_MESSAGE 环境变量
-pythongen_test_procedure.py
only:
-master# 只有合并到 master 分支时才触发,也可以是 develop
即使失败也不要阻塞 Pipeline 的最终结果
allow_failure:true
这里的 variables 会覆盖全局变量,但建议把敏感变量配在 GitLab Web UI 里
效果演示
当开发向 master 分支 push 了如下代码:
fix(user-profile): 修复用户修改头像时,特殊字符导致保存失败的问题。
几秒钟后,团队的测试群里就会收到机器人的 Markdown 消息:
🚀 收到新功能/修复提测
提交作者: Zhang San原始提交:fix(user-profile): 修复用户修改头像时...
AI 自动生成的测试规程 (仅供参考):
1️⃣ 测试场景
用户头像修改-特殊字符测试
2️⃣ 测试步骤
进入用户个人资料页面。
点击修改头像,选择一个文件名包含特殊字符(如 #@&%*.png)的图片。
点击保存。
3️⃣ 预期结果
头像应成功上传并预览,不会报错,且特殊字符被正确处理。
总结与工程权衡
这套流程在我们的团队实施后,最大的改变不是测试不用写用例了,而是极大地降低了沟通成本。
在“提测”这个动作发生的瞬间,测试同事实时得到了结构化的信息。哪怕 AI 生成的不完美,测试也只需要在这个基础上微调,而不是盯着几个单词冥思苦想。
最后,分享几个在工程落地时的权衡点:
AI 不是银弹: 脚本中我故意设置了 allow_failure: true,即使 AI 接口挂了或返回错误,也不会导致整个项目的 Pipeline 挂掉。自动化通知只是辅助,不能是硬约束。
模型的选择: 如果追求确定性,OpenAI 提供了强制 JSON 输出的功能。如果是国产模型,建议在 Prompt 中反复强调格式,并在 Python 代码中做好 Try-Catch 兜底。
规则与 AI 结合: 脚本中判断了 feat 和 fix 才触发,这就是一种结合。不要什么 commit 都去调用 AI,那叫浪费钱。
希望这篇文章能帮你构建起一条属于自己团队的自动化提测链路。有任何技术细节问题,欢迎评论区交流。