前言

这段时间因为一些特殊原因,一直在忙着写用例,有那么一丢丢小小的心得记录📝在此。
写用例的意义(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导入禅道
  1. 生成的用例输出为markdown格式
    直接在对话框输入:

    提供Markdown表格格式的测试用例,让我可以轻松地将其复制到Excel中。
    每列对应:用例标题、步骤、预期结果。
    

    生成的格式如下:

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

    然后就会导致脚本出错emmm

  3. Typro导出为HTML格式

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

  4. 将表格复制到excel文件

  5. 将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我可以直接导入到禅道。

遇到的问题

  1. 为什么不直接markdown格式转xmind。 – 我试试,可以的话我再写一篇。

总结

文章介绍了AI辅助测试用例编写的优化实践,核心价值是将AI能力与业务流程深度结合,大幅提升用例编写效率,减少重复性劳动。
PS:因为我司禅道上传时必须使用xmind8,xmind8使用此脚本没问题。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐