当前位置: 首页 > news >正文

AI 实践探索:辅助生成测试用例

背景

目前我们的测试用例主要依赖人工生成和维护,AI时代的来临,我们也在思考“AI如何赋能业务”,提出了如下命题:

“探索通过AI辅助生成测试用例,完成从需求到测试用例生成的穿刺”。

目标

  • 找全测试路径
  • 辅助生成测试用例

实践案例:登录注册流程

自然语言描述需求

需求名称:注册登录流程
需求描述:
1、注册和登录在同一个页面,有2个按钮,一个注册,一个登录,用户输入用户名、密码进行登录或者注册
2、首页:加载一张图,有个退出按钮,点击则退出首页

注:这里只是为了验证思路,需求描述会比较简单,实际需求考虑会更完善。

如何找全测试路径

使用LLM生成mermaid格式的状态机描述

使用Dify 搭建的工作流:

将前面的需求描述作为输入参数,提供Prompt模板告诉LLM,如下所示:

LLM 生成的mermaid 状态机描述:

stateDiagram-v2[*] --> UnregisteredUnregistered --> Registering: start_registerRegistering --> Unregistered: register_failedRegistering --> LoggingIn: register_successUnregistered --> LoggingIn: start_loginLoggingIn --> Unregistered: login_failedLoggingIn --> LoggedIn: login_successLoggedIn --> Unregistered: logoutLoggedIn --> [*]: exit

Markdown对mermaid支持友好,可以直接渲染成状态机图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里选择Mermaid来描述状态机的理由,主要是Mermaid天然适合文档化,代码轻量且无额外依赖,无需处理图片格式的一些问题。

参考:AI大模型生成的图表为什么倾向使用Mermaid格式?

使用AI帮我们开发工具

前面通过LLM能够帮我们理解需求生成状态机图,如果想基于状态机找全测试路径,我们尝试使用AI编程工具来辅助生成规则工具,来确保每次遍历的路径是一致的。

比如Cursor:

通过多轮的对话和人工修正,Cursor能够很高效的帮助我生成符合预期的代码,但仍需要人工去验证和调试。

核心路径生成算法:

from typing import List, Dict, Set
from abc import ABC, abstractmethodclass PathGeneratorBase(ABC):def __init__(self):self.graph = {}self.paths = []self.events = {}@abstractmethoddef parse_input(self):"""解析输入源(Mermaid或SCXML)"""passdef generate_paths(self, max_depth: int = 15) -> List[List[str]]:"""通用的路径生成算法"""paths = []start = self._find_start_state()visited_states = set()def dfs(current: str, path: List[str]):if len(path) > max_depth:returncurrent_transitions = self._get_transitions(current)if self._should_terminate(current, path, current_transitions):paths.append(path[:])returnvisited_states.add(current)for next_state in current_transitions:dfs(next_state, path + [next_state])visited_states.remove(current)dfs(start, [start])return self._deduplicate_paths(paths)def _find_start_state(self) -> str:"""查找起始状态"""if 'START' in self.graph:return 'START'in_degrees = self._calculate_in_degrees()for node, degree in in_degrees.items():if degree == 0:return nodereturn Nonedef _get_transitions(self, state: str) -> List[str]:"""获取状态的所有可能转换"""if state not in self.graph:return []return [target for target in self.graph[state]]def _should_terminate(self, current: str, path: List[str], transitions: List[str]) -> bool:"""判断是否应该终止当前路径"""return len(path) > 1 and (not transitions or current in path[:-1])def _deduplicate_paths(self, paths: List[List[str]]) -> List[List[str]]:"""去除重复路径"""unique_paths = []path_strings = set()for path in sorted(paths, key=len):path_str = "->".join(path)if path_str not in path_strings:path_strings.add(path_str)unique_paths.append(path)return unique_pathsdef calculate_coverage(self) -> Dict:"""计算测试覆盖率"""all_states = set(self.graph.keys())all_transitions = set()covered_states = set()covered_transitions = set()for path in self.paths:covered_states.update(path)for i in range(len(path) - 1):transition = (path[i], path[i + 1])covered_transitions.add(transition)all_transitions.add(transition)return {"state_coverage": len(covered_states) / len(all_states) * 100,"transition_coverage": len(covered_transitions) / len(all_transitions) * 100}

根据路径生成算法遍历生成的路径索引:

如何生成测试用例

用例关键要素

  • 前置条件:描述复现测试场景所需的条件;
  • 操作步骤:描述测试场景下用户的操作行为;
  • 预期结果:描述测试场景下,用户执行完操作预期得到的结果。

示例:

场景前置条件操作步骤预期结果
银行卡支付场景用户已绑定有效银行卡在收银台选择银行卡支付显示支付成功页面,账户余额减少相应金额

LLM 生成测试用例

工作流设计:

  1. 输入需求描述和测试路径
  2. 设计prompt提示词,要求LLM按固定格式输出测试用例

生成的测试用例结果示例:

[{"precondition": "用户未注册,系统处于未登录状态","operation_procedure": ["1. 访问系统首页","2. 输入用户名:a1_(3字符)","3. 输入密码:Passw0rd!","4. 点击'注册'按钮"],"expected_result": ["注册失败,提示'用户名长度需在4-20字符之间'","页面停留在注册/登录页面"]},{"precondition": "用户未注册,系统处于未登录状态","operation_procedure": ["1. 访问系统首页","2. 输入用户名:existing_user","3. 输入密码:Passw0rd!","4. 点击'注册'按钮","5. 再次输入相同用户名和密码点击'注册'按钮"],"expected_result": ["第二次注册时提示'用户名已存在'","页面停留在注册/登录页面"]},{"precondition": "用户未注册,系统处于未登录状态","operation_procedure": ["1. 访问系统首页","2. 输入用户名:user😊name","3. 输入密码:Passw0rd!","4. 点击'注册'按钮"],"expected_result": ["注册失败,提示'用户名包含非法字符'","页面停留在注册/登录页面"]},{"precondition": "用户未注册,系统处于未登录状态","operation_procedure": ["1. 访问系统首页","2. 输入不存在的用户名:new_user","3. 输入错误密码:wrongPass","4. 点击'登录'按钮"],"expected_result": ["登录失败,提示'用户名或密码错误'","页面停留在注册/登录页面"]},{"precondition": "用户已注册,系统处于未登录状态","operation_procedure": ["1. 访问系统首页","2. 输入已注册用户名:valid_user","3. 输入正确密码:Passw0rd!","4. 点击'登录'按钮"],"expected_result": ["登录成功,跳转至带图片的首页","页面显示退出按钮"]},{"precondition": "新用户完成注册,系统处于未登录状态","operation_procedure": ["1. 访问系统首页","2. 输入符合要求的用户名:new_user_123","3. 输入符合要求的密码:Passw0rd!","4. 点击'注册'按钮","5. 使用相同凭证点击'登录'按钮"],"expected_result": ["注册成功后自动清除表单","登录成功跳转至首页"]},{"precondition": "用户已登录,处于首页","operation_procedure": ["1. 点击'退出'按钮"],"expected_result": ["返回注册/登录页面","用户会话终止"]},{"precondition": "用户未注册,系统处于未登录状态","operation_procedure": ["1. 访问系统首页","2. 输入有效用户名:valid_user","3. 输入无效密码:password","4. 点击'注册'按钮"],"expected_result": ["注册失败,提示'密码需包含大写字母、小写字母、数字和特殊字符'","页面停留在注册/登录页面"]}
]

这里可以进一步将json数据转成xmind或excel格式的文件。

收益

价值思考? 几个方向:

  • AI辅助建模(状态机、类图),提升研发需求建模效率和规范
  • 释放助理生成测试用例的生产力,转变为review/修改用例的角色
  • AI辅助生成符合业务规则的可测试数据,提升构造数据的效率

经验总结

  • 使用AI帮助我们进行自然语言推理和图解析
  • 要让AI生成的测试用例更准确,需要精确描述需求,对需求进行建模,描述清楚业务规则
  • 使用AI编程工具帮助我们开发工具,比如有明确规则的工具开发
  • 通过搭建AI工作流完成需求穿刺

附录

  • Dify文档: https://docs.dify.ai/zh-hans

相关文章:

  • Redis 集群版本升级指南:从 Redis 7 升级到 Redis 8
  • Linux内核初始化机制全解析:从pure_initcall到late_initcall
  • Java高频面试之并发编程-13
  • Go语言八股之并发详解
  • 七彩喜微高压氧舱:探索健康与康复的新维度
  • Linux 内核学习(6) --- Linux 内核基础知识
  • Advanced Installer 22.5打包windows 安装包
  • 【Bluedroid】 HID 设备应用注册与主机服务禁用流程源码解析
  • 【Mybatis-plus常用语法】
  • 实验六 基于Python的数字图像压缩算法
  • 并发设计模式实战系列(17):信号量(Semaphore)
  • PostgreSQL 查询历史最大进程数方法
  • NumPy 2.x 完全指南【一】简介
  • Linux网络编程day6 下午去健身
  • JAVA中常见队列详解-非线程安全
  • MCP系列(一)什么是MCP?
  • DMA技术原理
  • 软件系统的可观测性 Observability
  • 鸿蒙开发中对want的深入理解,want和uiability的关系-深度理解want的意思有利开发-优雅草卓伊凡
  • 聊一聊Qwen3思考模式实现以及背后原理探讨
  • 成就彼此,照亮世界:“中欧建交50周年论坛”在沪成功举行
  • 2025上海十大动漫IP评选活动启动
  • 印称一名高级官员在巴基斯坦发动的袭击中死亡
  • 长江画派创始人之一、美术家鲁慕迅逝世,享年98岁
  • 奥园集团将召开债券持有人会议,拟调整“H20奥园2”本息兑付方案
  • 首届上海老年学习课程展将在今年10月举办