Agent用例生成进阶:从测试策略到Pytest代码

发布时间:2026/10/17 7:17:11

Agent用例生成进阶:从测试策略到Pytest代码 概述上一篇做了测试策略输入需求输出JSON。但CI流水线不认JSON它要的是pytest能跑的东西这篇就把测试策略转成Pytest代码。现在我们有策略策略里啥都有场景、预期、类型、优先级。把这些喂给AI需求进去代码出来中间不需要人动手。用例生成模块是做什么的输入测试策略JSON输出Pytest测试代码。具体点说输入是上一篇生成的策略功能名称、场景列表、步骤、预期结果。输出是一个完整的测试文件你拿过来就能用pytest命令跑。为什么要拆成两步把意图理解和用例生成合并成一步输入需求直接输出Pytest代码。听起来很爽少了一道工序但合在一起真的不好用。可能带来的问题出错了你找不到原因生成的代码挂了你不知道是需求理解错了还是代码生成环节出了岔子。日志里只有头和尾中间发生了什么是个黑盒。你想改没地方下手。策略生成错了你想手动改一下再重新生成。如果合并成一步你得重新跑一遍完整流程API费用再花一次。换个框架你得重写全部。同一个测试策略你可能想生成pytest版本的也可能想生成unittest版本的合并的话每种框架你得维护一套完整逻辑。拆开的话策略模块不用动只换生成模块就行。所以拆开更实用具体怎么做3.1 核心实现先写一个生成器类。# test_generation.pyimportjsonimportosfrompathlibimportPathfromtypingimportDict,Optionalfromdotenvimportload_dotenvfromopenaiimportOpenAIclassTestGenerationAgent: 用例生成Agent。 输入测试策略JSON和源代码输出Pytest测试代码。 def__init__(self,model:strgpt-4o):load_dotenv()self.clientOpenAI(api_keyos.getenv(OPENAI_API_KEY),base_urlos.getenv(OPENAI_BASE_URL,None))self.modelmodeldefgenerate(self,strategy:Dict,source_code:str,module_name:strapp)-str:根据测试策略和源代码生成Pytest测试代码。promptself._build_prompt(strategy,source_code,module_name)try:responseself.client.chat.completions.create(modelself.model,messages[{role:system,content:self._get_system_prompt()},{role:user,content:prompt}],temperature0.3)returnresponse.choices[0].message.contentexceptExceptionase:print(f用例生成失败:{e})returndef_get_system_prompt(self)-str:return 你是一位资深的测试开发工程师擅长用Pytest编写高质量的单元测试。 你的任务是根据提供的测试策略和源代码生成完整的Pytest测试代码。 要求 1. 测试代码必须覆盖策略中定义的所有场景 2. 使用pytest框架遵循最佳实践 3. 每个测试场景对应一个测试方法 4. 方法名用test_开头后面跟场景的英文标识 5. 使用pytest.raises处理异常场景 6. 添加适当的注释说明每个测试的用途 7. 代码风格清晰、规范 8. 只输出Python代码不要额外解释 def_build_prompt(self,strategy:Dict,source_code:str,module_name:str)-str:scenariosstrategy.get(test_scenarios,[])scenario_textjson.dumps(scenarios,indent2,ensure_asciiFalse)returnf#下面是待测试的源代码{source_code}#下面是测试策略包含需要覆盖的测试场景{scenario_text}# 请为 {module_name} 模块生成完整的Pytest测试代码。defsave_test_code(code:str,filepath:strtest_generated.py):withopen(filepath,w,encodingutf-8)asf:f.write(code)print(f测试代码已保存:{filepath})3.2 如何使用加载上一篇生成的测试策略传入源代码调用生成器。if__name____main__:# 加载上一篇生成的测试策略withopen(login_strategy.json,r,encodingutf-8)asf:strategyjson.load(f)# 被测试的源代码source_code # login.py class UserService: def __init__(self): self._users { 13800001111: {password: 123456, nickname: 张三, locked: False}, testexample.com: {password: 123456, nickname: 李四, locked: False}, } self._login_attempts {} self._locked_accounts {} def login(self, account: str, password: str) - dict: if account not in self._users: return {success: False, message: 账号不存在} user self._users[account] if user.get(locked, False): return {success: False, message: 账号已被锁定请联系客服} if account in self._locked_accounts: lock_time self._locked_accounts[account] if lock_time 0: return {success: False, message: 账号已被锁定30分钟} if user[password] ! password: self._login_attempts[account] self._login_attempts.get(account, 0) 1 if self._login_attempts[account] 5: self._locked_accounts[account] 30 return {success: False, message: 因多次登录失败账号已被锁定30分钟} return {success: False, message: 密码错误} self._login_attempts[account] 0 return { success: True, message: 登录成功, nickname: user[nickname] } agentTestGenerationAgent()test_codeagent.generate(strategy,source_code,login)iftest_code:save_test_code(test_code,test_login.py)print(\n生成的测试代码\n)print(test_code)else:print(生成失败)3.3 AI生成的代码运行上面的脚本test_login.py的内容大概是这样的。# test_login.pyimportpytestfromloginimportUserServiceclassTestUserLogin:用户登录功能的测试套件defsetup_method(self):每个测试方法执行前重置状态self.serviceUserService()deftest_login_with_phone_success(self):TC-001: 使用手机号正确登录resultself.service.login(13800001111,123456)assertresult[success]isTrueassertresult[message]登录成功assertresult[nickname]张三deftest_login_with_email_success(self):TC-002: 使用邮箱正确登录resultself.service.login(testexample.com,123456)assertresult[success]isTrueassertresult[message]登录成功assertresult[nickname]李四deftest_login_account_not_exist(self):TC-003: 登录失败-账号不存在resultself.service.login(13900001111,123456)assertresult[success]isFalseassertresult[message]账号不存在deftest_login_wrong_password(self):TC-004: 登录失败-密码错误resultself.service.login(13800001111,wrongpass)assertresult[success]isFalseassertresult[message]密码错误deftest_login_account_locked_by_admin(self):TC-005: 登录失败-账号被锁定self.service._users[13800001111][locked]Trueresultself.service.login(13800001111,123456)assertresult[success]isFalseassertresult[message]账号已被锁定请联系客服deftest_login_trigger_lock_after_5_failures(self):TC-006: 连续输错密码触发锁定account13800001111foriinrange(5):resultself.service.login(account,wrongpass)ifi4:assertresult[message]密码错误else:assertresult[message]因多次登录失败账号已被锁定30分钟assertresult[success]isFalsedeftest_login_paste_disabled(self):TC-007: 密码框禁止粘贴# 这个场景是前端约束单元测试测不了# 实际项目中需要UI自动化测试覆盖pytest.skip(前端约束需要UI自动化测试验证)deftest_login_response_time(self):TC-008: 登录接口响应时间importtime starttime.time()self.service.login(13800001111,123456)elapsed(time.time()-start)*1000assertelapsed500,f响应时间{elapsed}ms超过500ms策略里的8个场景变成了8个测试方法。每个方法对应一个场景断言也写好了。3.3 把两步串起来下面这个脚本把意图理解和用例生成串成一条线。# end_to_end.pyimportjsonfromintent_understandingimportIntentUnderstandingAgentfromtest_generationimportTestGenerationAgentdefrun_end_to_end(requirement:str,source_code:str,module_name:strapp):print(*50)print(Step 1: 意图理解)print(*50)intent_agentIntentUnderstandingAgent()strategyintent_agent.understand(requirement)iferrorinstrategy:print(f失败:{strategy[error]})returnprint(f生成{len(strategy.get(test_scenarios,[]))}个场景)withopen(strategy_output.json,w,encodingutf-8)asf:json.dump(strategy,f,indent2,ensure_asciiFalse)print(策略已保存: strategy_output.json)print(\n*50)print(Step 2: 用例生成)print(*50)gen_agentTestGenerationAgent()test_codegen_agent.generate(strategy,source_code,module_name)ifnottest_code:print(生成失败)returnwithopen(test_output.py,w,encodingutf-8)asf:f.write(test_code)print(测试代码已保存: test_output.py)print(\n*50)print(完成)print(*50)print(f场景数:{len(strategy.get(test_scenarios,[]))})print(下一步: pytest test_output.py -v)if__name____main__:requirement 需求用户登录功能 用户可以使用手机号或邮箱进行登录。 登录时需要验证密码是否正确。 登录成功后的行为 - 跳转到个人主页 - 在顶部显示用户昵称 登录失败的场景 - 手机号/邮箱不存在提示账号不存在 - 密码错误提示密码错误 - 账号被锁定提示账号已被锁定请联系客服 安全要求 - 连续输错5次密码后账号锁定30分钟 source_code class UserService: def __init__(self): self._users { 13800001111: {password: 123456, nickname: 张三, locked: False}, } self._login_attempts {} self._locked_accounts {} def login(self, account: str, password: str) - dict: if account not in self._users: return {success: False, message: 账号不存在} user self._users[account] if user.get(locked, False): return {success: False, message: 账号已被锁定请联系客服} if account in self._locked_accounts: return {success: False, message: 账号已被锁定30分钟} if user[password] ! password: self._login_attempts[account] self._login_attempts.get(account, 0) 1 if self._login_attempts[account] 5: self._locked_accounts[account] 30 return {success: False, message: 因多次登录失败账号已被锁定30分钟} return {success: False, message: 密码错误} self._login_attempts[account] 0 return {success: True, message: 登录成功, nickname: user[nickname]} run_end_to_end(requirement,source_code,login)跑完之后执行pytest test_output.py-v看到测试通过的那一刻整个流程就闭环了。需求进去代码出来中间不用你写一行。常见问题Q1生成的代码能直接用吗最好检查一遍。AI偶尔会犯错。import路径不对或者依赖的类名写错了。大问题不多小毛病难免。但比自己从头写还是能省了至少一个小时的时间Q2代码跑不通怎么办把报错信息贴给AI让它自己改。这是目前最省事的做法。把pytest的输出复制下来跟原始代码一起发给AI告诉它这段测试挂了帮我修一下。大部分情况下AI能自己搞定。Q3场景太多了生成慢怎么办拆成几批。如果一个策略有20多个场景你可以分两批生成。先让AI生成前10个保存。再生成后10个追加到同一个文件。这样每次请求的数据量小一些响应快也不容易超出AI的上下文窗口。Q4项目代码风格不一样怎么办把规范写进prompt里。比如你们项目要求测试类必须继承某个基类或者必须用特定的fixture。把这些要求写进系统提示词AI会照着做。如果你想做得更细致可以在项目里放一个规范文件每次生成之前让AI先读一遍。总结意图理解管出策略用例生成出代码中间用JSON对接。整个流程是这样的需求描述 → 测试策略 → Pytest代码 → pytest执行前三步我们已经能自动跑通了第四步就是pytest自己的事。
延伸阅读

更多相关文章

2026/10/15 12:26:23

C++函数指针语法和类型

函数指针是 C/C 中一种将函数地址作为变量存储和传递的机制,它允许程序在运行时动态选择并调用不同的函数,是实现回调、策略模式和插件系统的核心基础。核心语法结构函数指针的声明语法遵循“返回类型 (*指针名)(参数列表)”的格式。例如,声明…

2026/10/16 14:12:30

Go服务生产环境的生存规则,你知道几条?

Go 让你很容易就能写出一段“能编译、能通过冒烟测试、一遇到真实流量就跪”的代码。这门语言默认给你很少——没有运行时异常可以捕获,没有框架护栏,没有魔法。这是个特性,但这也意味着:让一个服务在生产环境活下去的规则&#x…

2026/10/14 20:43:22

Open-Connector:开源连接器网关,解决AI Agent接入SaaS服务难题

【导语:Open-Connector作为面向AI Agent和应用开发者的开源连接器网关,旨在解决AI Agent接入外部SaaS服务的系列问题,提供丰富的连接器目录和预构建Actions,适用于多种类型项目。】开源网关解决AI Agent接入难题Open-Connector是一…

2026/10/17 10:30:15

Spire.Doc水印清除实战:绕过API失效的文档级干预方案

简介:本资源是面向C#开发者与.NET文档处理工程师的Spire.Doc水印清除实战方案,聚焦Word文档中内置及自定义水印(如‘草稿’‘机密’文字水印、半透明背景图)的精准识别与自动化移除。资源包共31个文件,含15个核心DLL&a…

2026/10/17 10:30:15

NVIDIA PAIR中文部署完全指南:把家里电脑串成AI算力集群

NVIDIA PAIR中文部署完全指南:把家里电脑串成AI算力集群 2026年9月3日,英伟达开源了Personal AI Router(PAIR)——一款能在局域网内自动调度AI推理请求的"个人AI路由器"。它不是模型,不生成内容&#xff0c…

2026/10/17 10:30:15

电子学会科学技术奖申报答辩PPT定制|突出项目硬核实力

中国电子学会科学技术奖是经国家科技奖励工作办公室批准,由中国电子学会于2003年设立的奖项,主要奖励在电子信息领域科学研究、技术创新与开发、科技成果推广应用和实现产业化方面取得卓著成绩或者做出突出贡献的集体和个人。该奖项共设立‌5 个奖种‌&a…

2026/10/17 10:30:15

HSV、RGB与十六进制颜色换算:JavaScript实现与精度边界处理

1. 颜色换算到底在解决什么问题前端开发做久了,你会发现颜色这东西几乎无处不在。设计稿标注的是十六进制色值,比如#3A7BD5;取色器吸出来的是 RGB 三元组,比如rgb(58, 123, 213);而做调色板、渐变生成、主题色推导的时…

2026/10/17 10:30:15

class java.util.LinkedHashMap cannot be cast to xxx

错误复现这个报错是在学习微服务的过程中发现的,涉及到 Feign 远程调用。一共有两个服务:user 和 user2。user 的 Feign 接口如下:FeignClient("user") public interface UserClient {GetMapping("/user/getUser")Result…

2026/10/17 10:25:15

YOLOv8工业落地避坑指南:从数据清洗到TensorRT部署

简介:本资源是一套基于YOLOv8的图像识别完整实践项目,面向计算机视觉初学者与Python深度学习开发者,聚焦目标检测任务的端到端实现,适用于安全监控、工业质检、智能相册等典型应用场景。压缩包共53个文件,含10个核心Py…

2026/10/16 5:33:43

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/16 4:03:48

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/17 0:04:32

PlanarSLAM:面向曼哈顿世界的点线面联合SLAM系统

简介:本资源是面向机器人视觉与SLAM研究者的C开源RGB-D SLAM系统实现,专为结构化室内场景(如办公室、走廊)设计,通过融合点、线、平面三类几何特征并引入“曼哈顿世界”假设,显著提升位姿跟踪鲁棒性与稠密地…

2026/10/17 0:04:32

TDH Workflow调度实战:从DAG依赖驱动到任务编排与故障排查

1. 从一个调度脚本说起:TDH Workflow到底在解决什么问题第一次接触TDH的Workflow,是在一个数据清洗项目里。当时团队每天要跑几十个ETL任务,任务之间有严格的先后依赖——A表清洗完才能跑B表的关联,B表跑完才能触发C表的聚合。最开…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑