AI写用例的一点心得(内容包含AI生成用例+excel转xmind格式代码)
前言
这段时间因为一些特殊原因,一直在忙着写用例,有那么一丢丢小小的心得记录📝在此。
写用例的意义(emmm突然变成了哲学家😂,开始思考意义),一是熟悉需求,设计测试场景时,需求中不清楚的问产品;二是可能一些公司测试的绩效和用例数挂钩。
步骤
我们公司从写用例到上传的步骤如下:
- 用xmind写
xmind写用例 -> 上传禅道
两个步骤🤔,该怎么进行优化呢。
xmind写用例优化
首先是写用例,使用AI+手写补场景的方法进行编写。
1. 模型的选择
用哪个模型大模型看个人喜好吧。我试过Grok,豆包,DeepSeek,通义等,最后用的是DeepSeek。通义我一般用来写代码,豆包我用来生成图片(博客封面图等),Grok离开一会就要验证,有点烦。
2. 设置好提示词
上传了prd给模型后,再根据自己要求来编写提示词,下面是我写的一段:
只编写4、基础数据配置-车辆维护字段枚举变更的用例
- 只生成功能测试用例,需覆盖核心功能、关键边界值、常见异常场景
- 严格符合模板:
用例标题: 任务派发日志 - 根据查询条件部分导出数据[C,P:3] (任务派发日志 + 【用一句话清晰阐明测试目标和被测功能点】+[C,P:3])
步骤:
1.进入HOC进退群监控页面。
预期:
1.页面正常加载。
- 新增/编辑页是否有字段【车辆品牌】(1条),文本框字符数限制(49/50/51字符,3条)
- 新增/编辑页,【车型】字段枚举值无“考斯特”、“全顺”、“奔驰”;增加“内场摆渡车”、“外场车”、“移动电源车”(1条)
- 新增/编辑页,油电:删除“混动”,变更为“无动力设备”(1条)
- 新增/编辑页,【车辆状态】字段枚举值删除“损坏”,新增“故障”、“维修”、“保养”、“报废”(1条)
- 临时任务“车辆送修/取回”只能选择”故障“状态的车牌号(1条)
这段话由两部分构成:【范围、要求、格式控制】 + 【用例具体的要求和条数】。
【范围、要求、格式控制】这么写是因为:
- 大模型一次生成的用例数有限
- 如果指定生成多少条左右,模型会为了凑数生成许多无用的用例如安全性测试这些( 例如SQL 注入攻击这类测试用例),而现在的后端框架针对简单的安全性测试已经集成的很成熟了,所以不是为了凑数(小声bb)的话可以不写
- 模版的话,每个公司的模版都不相同,按照一定的模版生成是为了更加方便导入用例。
【用例具体的要求和条数】这么写是因为:
- 能够更好地控制生成的用例的质量,免得返工修改用例以及补充漏写场景浪费时间
格式优化
生成完用例之后,需要按照特定的格式导入到禅道里。但是模型生成的用例不可以直接转换为xmind格式,所以我将模型生成的用例转换为markdown格式,再在Typro中将用例导出为HTML,将用例复制到excel文件中,再用python脚本转为xmind导入到禅道(听起来很烦是不😫其实俺在写文章时就意识到,为啥不直接markdown转xmind呢)。
简单说来过程如下:
生成的用例输出为markdown -> 复制到Typro中 ->Typro导出为HTML格式
-> 将用例复制到excel文件里-> excel转xmind导入禅道
-
生成的用例输出为markdown格式
直接在对话框输入:提供Markdown表格格式的测试用例,让我可以轻松地将其复制到Excel中。 每列对应:用例标题、步骤、预期结果。生成的格式如下:

-
复制到Typro中

这里直接复制表格到excel中就会出现如下的问题:
这样后面使用脚本将excel转xmind时就会出现问题。
出现这种问题是因为Typora 编辑模式下,表格是 Markdown 源码(用|分隔列、-分隔行),此时复制的是「纯文本字符串」;Excel 会把整行源码当成一个单元格内的文本,不会自动拆分。ps:在导出之前建议将所有的换行符号即<br>替换为空格;因为如果不替换待会复制到excel中时就会出现如下情况:
然后就会导致脚本出错emmm -
Typro导出为HTML格式

这里我试了其他格式(PDF,Word等复制出来的表格都不大行) -
将表格复制到excel文件

-
将excel转为xmind
import xmind
import os
import shutil
import zipfile
from openpyxl import load_workbook
file_path = os.path.dirname(os.path.realpath(__file__))
class convert:
def extract(self, d_path, f_path):
"""
zip解压缩乱码问题处理
:param d_path:
:param f_path:
:return:
"""
global zf
# os.chdir(root_path)
root = d_path
if not os.path.exists(root):
os.makedirs(root)
# print('ffff',os.getcwd())
zf = zipfile.ZipFile(f_path,"r")
for n in zf.infolist():
srcName = n.filename
try:
decodeName = srcName.encode("cp437").decode("utf-8")
except:
try:
decodeName = srcName.encode("cp437").decode("gbk")
except:
decodeName = srcName
spiltArr = decodeName.split("/")
path = root
for temp in spiltArr:
path = os.path.join(path, temp)
if decodeName.endswith("/"):
if not os.path.exists(path):
os.makedirs(path)
else:
if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path))
f = open(path, "wb")
f.write(zf.read(srcName))
f.close()
zf.close()
# 修复无法打开xmind文件的问题
def aftertreatment(self, path):
# 修改名字
retval = os.path.dirname(os.path.abspath(__file__))
folder = os.path.dirname(path)
name = os.path.basename(path)
unzip_folder = os.path.splitext(name)[0]
zip_name = unzip_folder + ".zip"
os.chdir(folder)
os.rename(name, zip_name)
os.chdir(retval)
# 解压
unzip_path = os.path.join(folder, unzip_folder)
if not os.path.exists(unzip_path):
os.mkdir(unzip_path)
inf_folder = os.path.join(unzip_path, "META-INF")
if not os.path.exists(inf_folder):
os.mkdir(inf_folder)
self.extract(unzip_path, os.path.join(folder, zip_name))
shutil.copyfile("./main_fest.xml", os.path.join(inf_folder, "manifest.xml"))
os.remove(os.path.join(folder, zip_name))
shutil.make_archive(unzip_path, 'zip', unzip_path)
file_path = unzip_path + '.zip'
# print(file_path)
os.chdir(os.path.dirname(file_path))
os.rename(os.path.basename(file_path), name)
os.chdir(retval)
shutil.rmtree(unzip_path)
# 转化成xmind文件
def gen_xmind_file(self, xls):
global sub_topic
readbook = load_workbook(xls)
sheet_list = readbook.sheetnames
count_sheets = len(sheet_list)
try:
for i in range(count_sheets):
sheet_name = sheet_list[i]
workbook = xmind.load(sheet_name + '.xmind')
first_sheet = workbook.getPrimarySheet()
root_topic = first_sheet.getRootTopic()
root_topic.setTitle(sheet_name)
# ✅【最小改动】新增第二层级节点 1117
level2_topic = root_topic.addSubTopic()
level2_topic.setTitle("1117")
sheet = readbook[sheet_name]
for row in list(sheet.rows)[1:]:
for c in range(len(row)):
m = 0
value = row[c].value
print(value)
if c == 0:
# ✅ 改为在 level2_topic 下查找/添加子节点
if len(level2_topic.getSubTopics()) == 0:
sub_topic = level2_topic.addSubTopic()
sub_topic.setTitle(value)
else:
for j in level2_topic.getSubTopics():
m += 1
if value == j.getTitle():
sub_topic = j
break
elif m == len(level2_topic.getSubTopics()):
sub_topic = level2_topic.addSubTopic()
sub_topic.setTitle(value)
else:
if len(sub_topic.getSubTopics()) == 0:
sub_topic = sub_topic.addSubTopic()
sub_topic.setTitle(value)
else:
for k in sub_topic.getSubTopics():
m += 1
if value == k.getTitle():
sub_topic = k
break
elif m == len(sub_topic.getSubTopics()):
sub_topic = sub_topic.addSubTopic()
sub_topic.setTitle(value)
# xmind.save(workbook, path=sheet_name + '.xmind')
xmind.save(workbook, path=r'./' + sheet_name + '.xmind')
# 修复
output_dir = './output/'
if not os.path.exists(output_dir):
os.makedirs(output_dir)
xmind.save(workbook, path=os.path.join(output_dir, sheet_name + '.xmind'))
return 'OK'
except Exception as e:
print("Error:", e) # 建议保留异常信息便于调试
pass
if __name__ == '__main__':
convert().gen_xmind_file(xls=r'./input/3.xlsx') # 改个文件路径就能用
输出的xmind如下:
这种格式的xmind我可以直接导入到禅道。
遇到的问题
- 为什么不直接markdown格式转xmind。 – 我试试,可以的话我再写一篇。
总结
文章介绍了AI辅助测试用例编写的优化实践,核心价值是将AI能力与业务流程深度结合,大幅提升用例编写效率,减少重复性劳动。PS:因为我司禅道上传时必须使用xmind8,xmind8使用此脚本没问题。
更多推荐

所有评论(0)