AI辅助编程的边界探索:当Copilot学会写测试

AI辅助编程的边界探索:当Copilot学会写测试
在这里插入图片描述
👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕人工智能这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!

文章目录

AI辅助编程的边界探索:当Copilot学会写测试 🚀

在过去的几年里,我们见证了人工智能辅助编程工具(如 GitHub Copilot、Cursor 等)从简单的代码补全插件,进化成为能够独立思考、生成复杂逻辑的“数字伙伴”。大多数开发者的使用场景停留在“帮我写个排序算法”或者“帮我补全这个React组件的样式”。然而,当AI开始染指软件工程中最繁琐、最需要逻辑严密性的领域——测试(Testing) 时,一切都变得有趣且充满挑战。

今天,我们就来深入探讨一下:当Copilot学会了写测试,它的边界在哪里?它能否取代人工编写测试用例的工作?它又会在哪里“翻车”? 让我们通过一系列真实的代码实验来寻找答案 📝。


1. 从“写代码”到“验代码”:AI的新战场 ⚔️

传统的编程教学往往强调如何实现功能(Implementation),而软件工程的核心却有一半是维护。维护的核心不是加功能,而是保证加功能不破坏旧功能。这就使得测试变得至关重要。

对于AI来说,写一段计算斐波那契数列的代码是简单的,因为逻辑是收敛的。但是,写一段针对斐波那契数列的测试用例则是发散的:你要考虑输入0、输入负数、输入超大数、溢出处理等等。AI写测试的核心难点在于:它不知道产品的“意图”(Intent),它只能根据上下文进行“模仿”。

下面,我们构建一个典型的业务场景,来测试Copilot的能力边界。我们将使用 TypeScriptJest 作为实验环境。

场景设定:一个简单的支付网关模拟器 💳

我们需要一个看似简单但包含逻辑分支的函数。

// paymentService.tsinterfacePaymentRequest{ userId:string; amount:number; currency:'USD'|'CNY'|'EUR';}interfacePaymentResult{ success:boolean; transactionId?:string; error?:string;}exportconst processPayment =(req: PaymentRequest): PaymentResult =>{// 业务逻辑:金额必须大于0if(req.amount <=0){return{ success:false, error:'Invalid amount'};}// 业务逻辑:如果是测试用户,直接返回成功if(req.userId.startsWith('test_')){return{ success:true, transactionId:'test_tx_123'};}// 模拟外部支付API调用(这里假设总是成功)const txId =`tx_${Math.random().toString(36).substr(2,9)}`;return{ success:true, transactionId: txId };};

现在,如果我们直接告诉AI:“为这个文件写测试”,会发生什么?


2. 初级实验:AI能写出“Happy Path”吗? ✅

“Happy Path”(快乐路径)指的是测试用例中最理想、最常见的流程,比如“用户付了钱,系统返回成功”。

Prompt:// Write unit tests for processPayment function using Jest

Copilot (or similar AI) 生成的代码:

// paymentService.test.tsimport{ processPayment }from'./paymentService';describe('processPayment',()=>{// 测试正常的正向流程it('should return success for valid payment',()=>{const request ={ userId:'user_123', amount:100, currency:'USD',};const result =processPayment(request);expect(result.success).toBe(true);expect(result.transactionId).toBeDefined();});// 测试金额为0的情况it('should fail when amount is zero',()=>{const request ={ userId:'user_123', amount:0, currency:'USD',};const result =processPayment(request);expect(result.success).toBe(false);expect(result.error).toBe('Invalid amount');});});

分析: 这是标准的“模板式”测试。AI完美地识别了代码中的两个 if 分支,并生成了对应的断言。这是 Copilot 最擅长的地方,它本质上是在做“模式匹配”。

但是,这引出了我们的第一个疑问:如果我们不告诉它需要测试“负数金额”,它会主动写吗?通常不会。这暴露了AI的第一个盲区:被动响应,而非主动发现缺陷。


3. 进阶实验:Mocking 与 外部依赖 🎭

在真实的项目中,你的函数通常不是独立的,它会调用数据库、调用第三方API(Stripe, PayPal等)。测试必须将这些外部依赖 Mock(模拟) 掉。这才是考验AI逻辑理解能力的地方。

让我们修改代码,引入一个真实的异步外部调用。

// database.ts (模拟数据库)exportconstsaveTransaction=async(data:any)=>{// 这里连接了真实的数据库return{ id:'db_123',...data };};
// orderService.tsimport{ saveTransaction }from'./database';exportconstcreateOrder=async(items:string[], userId:string)=>{if(!items.length)thrownewError('Cart is empty');const order ={ items, userId, createdAt:newDate()};const saved =awaitsaveTransaction(order);return saved;};

Prompt:// Write tests for createOrder and mock the database module

AI 生成的代码:

// orderService.test.tsimport{ createOrder }from'./orderService';import{ saveTransaction }from'./database';// 关键步骤:Mocking jest.mock('./database',()=>({ saveTransaction: jest.fn(),}));describe('createOrder',()=>{it('should save order to database',async()=>{// Arrangeconst mockSave = saveTransaction as jest.Mock; mockSave.mockResolvedValue({ id:'mock_id'});// Actconst result =awaitcreateOrder(['item1'],'user_1');// Assertexpect(mockSave).toHaveBeenCalled();expect(result.id).toBe('mock_id');});it('should throw error if cart is empty',async()=>{awaitexpect(createOrder([],'user_1')).rejects.toThrow('Cart is empty');});});

** verdict (评判)😗*
这一波操作非常漂亮 😎。AI不仅自动生成了 jest.mock,还正确处理了异步函数 (async/await)。这说明在基于上下文的单元测试场景下,AI已经达到了相当高的可用性。

但是,精彩的地方来了。如果我们稍微修改一下业务逻辑,增加一个边界条件,AI的表现会如何?


4. 陷阱与幻觉:AI写测试时犯的那些错 🤪

AI并不真正“理解”代码,它只是根据统计学预测最可能的下一段文本。这导致它在处理边界值特定业务规则时,会产生令人啼笑皆非的“幻觉测试”。

案例 A:永远不会错的测试

假设我们有一段非常糟糕的代码(或者AI根本看不懂的混淆代码):

// weirdLogic.tsexportconstgetStatus=(code:number)=>{if(code >100)return'OK';return'ERROR';};

如果你让AI测试它,AI会根据代码生成:

it('should return OK for code > 100',()=>{expect(getStatus(101)).toBe('OK');});

这看起来没问题。但是,如果产品需求变了,实际上业务规则应该是 code >= 100(大于等于)呢?AI不会质疑代码,它会忠实且错误地测试错误的代码。这就是所谓的 “测试覆盖了代码,但验证了错误”

案例 B:永远跑不通的断言

有时候,AI会写出看似合理,但运行时永远无法通过的断言。

Prompt:// Test that the array contains unique elements

假设我们的原始数组是 [1, 2, 3, 3](有重复),AI可能会生成这样的测试:

it('should contain only unique elements',()=>{// 假设这里返回了 [1, 2, 3, 3]const result =getData();const unique =newSet(result);// AI的幻觉:它假设 Set 后长度等于原始长度expect(unique.size).toBe(result.length);});

如果你运行这个测试,它会 Fail。但开发者看到 Fail 后,往往会去改代码(试图让数组没有重复),而不是意识到这个测试用例本身是基于错误的假设(数据源本身可能有重复,这不是一个Bug,而是一个业务事实)。AI制造了新的“伪Bug”。

案例 C:复杂集成测试的无力

在端到端(E2E)测试或者集成测试中,AI的表现会指数级下降。因为这需要AI理解状态(State)

想象一下,你需要测试:“用户登录 -> 添加购物车 -> 点击结算 -> 验证库存扣减 -> 验证支付回调 -> 验证数据库订单状态”。

这种长达10步的流程,AI很难一次性生成完整的 Flow。除非你在极其细粒度的 Prompt 中,详细描述每一步的数据库状态和预期结果。


5. 人机协作:重新定义测试工作流 🤝

既然AI不是万能的,那么最佳的策略就是利用AI的吞吐量,配合人类的判断力。让我们用 Mermaid 图表来展示这个新时代的测试工作流。

在这个流程中,AI不再是执行者,而是协作者

渲染错误: Mermaid 渲染失败: Parse error on line 3: ...--> C[AI: 自动生成基础测试桩 (Stubs)] C --> D -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'

如上图所示,AI负责第一层的覆盖(Happy path + 基本的 Mock),而人类负责最深层的逻辑校验

实践技巧:如何高效地让AI写测试?

  1. 不要只说“写测试”
    • // write tests
    • // Write unit tests for this function, specifically testing the error handling when input is null and the currency conversion logic for USD to EUR.
  2. 指定测试框架
    明确告诉它用什么工具(例如 Jest, Mocha, PyTest),它能生成更精准的脚手架。
  3. 让它扮演 QA 工程师
    使用 Prompt: Act as a QA engineer. What edge cases should I test for this login function? (扮演QA工程师,我应该测试这个登录函数的哪些边界情况?)。通常它会列出一堆你没想到的negative case,比如SQL注入测试、并发登录测试等。

6. 展望未来:AI会取代测试工程师吗? 🔮

目前的AI,包括Copilot,在测试领域的定位应该是 “高级助理”,而不是“独立工作者”。

AI目前的强项:

  • 生成样板代码(Boilerplate)。
  • 编写针对确定逻辑的单元测试。
  • 批量生成 Mock 代码。
  • 将代码转化为测试(如果你有一段代码,它能帮你写测试)。

AI目前的弱项:

  • 理解真实的业务意图(Context)。
  • 编写性能测试和压力测试。
  • 维护测试(当代码重构后,测试需要同步更新,AI往往会照着旧代码生成新的错误测试)。
  • 探索性测试(Exploratory Testing)。

结论是:Copilot能把测试的门槛降低,但无法把测试的质量拉高。 质量取决于人类对业务的理解深度。

最后,推荐大家在使用AI辅助编程时,配合阅读一下官方的最佳实践,比如 Jest 官方文档 中关于异步测试的章节,或者 MDN Web Docs 上关于单元测试的基础概念。

让我们拥抱变化,利用工具,但永远保持怀疑精神 👀。毕竟,代码可能会说谎,但测试不能。


如果你想了解更多关于TDD(测试驱动开发)的哲学,可以参考 Wikipedia - Test-driven development


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Read more

AI 原生架构:鸿蒙App的下一代形态

AI 原生架构:鸿蒙App的下一代形态

子玥酱(掘金 / 知乎 / ZEEKLOG / 简书 同名) 大家好,我是子玥酱,一名长期深耕在一线的前端程序媛 👩‍💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。 我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括前端工程化、小程序、React / RN、Flutter、跨端方案, 在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。 技术方向:前端 / 跨端 / 小程序 / 移动端工程化 内容平台:掘金、知乎、ZEEKLOG、简书 创作特点:实战导向、源码拆解、少空谈多落地 文章状态:长期稳定更新,大量原创输出 我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在“API 怎么用”,而是更关注为什么这么设计、在什么场景下容易踩坑、

我用百度智能云跑OpenClaw,AI帮我24小时盯盘、找黑马

OpenClaw(也就是Clawdbot)爆火,成为2026年现象级AI应用,被业界认为是Agent今后的主要发展方向。简单来说,它是一个能够自己操作电脑干活的智能体,你只需要通过聊天工具给他发指令,它就会自动规划和执行任务。 一位博主给了OpenClaw 50美元,让它自生自灭,结果AI通过高频捕捉套利机会,在交易当中获利,仅48小时之内将50美元滚到了2980美元。 这个案例给了我启发:何不让OpenClaw来帮我赚钱,给他操盘思路,复现一个AI炒股大神,并且让大多数人都能轻松抄作业。 于是我开始尝试,首先要搞定OpenClaw的部署,我推荐使用云主机的部署方式,国内各家科技公司都提供了OpenClaw接入服务,下面以百度智能云为例,简单说下部署的过程。 01 百度智能云:轻松部署,极简交互 打开百度智能云官网,现在每天开放 500 个名额,可以一分钱开通,快抢福利吧: https://cloud.baidu.com/product/BCC/moltbot.html 确认订单、完成支付后,就可以准备安装和配置了。

人工智能:大语言模型(LLM)原理与应用实战

人工智能:大语言模型(LLM)原理与应用实战

人工智能:大语言模型(LLM)原理与应用实战 1.1 本章学习目标与重点 💡 学习目标:掌握大语言模型的核心原理、训练流程与微调方法,学会基于开源大语言模型完成定制化对话与文本生成任务。 💡 学习重点:理解大语言模型的Transformer decoder-only架构,掌握指令微调与RLHF技术,能够使用LoRA高效微调开源LLM。 1.2 大语言模型的核心概念与发展历程 1.2.1 什么是大语言模型 💡 大语言模型(Large Language Model, LLM)是参数量达到十亿级甚至万亿级的Transformer-based模型。它通过在海量文本数据上进行预训练,学习语言的语法、语义、常识和推理能力。 LLM的核心能力包括文本生成、理解、翻译、摘要、问答等。它可以处理复杂的自然语言任务,无需针对每个任务单独设计模型结构。 LLM与传统NLP模型的核心区别: * 参数量级:传统模型参数量通常在千万级,LLM参数量可达十亿到万亿级。 * 训练数据:传统模型依赖标注数据,LLM使用海量无标注文本进行预训练。 * 能力边界:传统模型只能处理单一任务,LL

酒馆SillyTavern使用第三方API接口,打造专属AI聊天

酒馆SillyTavern使用第三方API接口,打造专属AI聊天

一、酒馆SillyTavern简介 SillyTavern(简称 ST,中文俗称酒馆)是一个本地安装的用户界面,可让你与文本生成 LLM、图像生成引擎和 TTS 语音模型进行交互。我们的目标是让用户尽可能地发挥实用性并控制他们的 LLM 提示,让陡峭的学习曲线成为乐趣的一部分。 二、安装 为何要使用酒馆? SillyTavern 相比 ChatGPT/Claude/Gemini 等 LLM 服务的网页或 App 聊天界面,能够提供更高的灵活性。 SillyTavern 是一款可实现以下用途的应用程序: 它是一个处理与 AI 语言模型通信的用户界面。 它可以让你创建新的角色卡(提示),并轻松地在它们之间切换。 它允许你导入其他人创建的角色。 它将保留你与角色的聊天记录,允许你随时恢复、开始新聊天、查看旧聊天等。 在后台,它会为你准备 AI 提示。具体来说,它会发送系统提示(给