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

一文熟悉新版llama.cpp使用并本地部署LLAMA

一文熟悉新版llama.cpp使用并本地部署LLAMA

0. 简介 关于UCloud(优刻得)旗下的compshare算力共享平台 UCloud(优刻得)是中国知名的中立云计算服务商,科创板上市,中国云计算第一股。 Compshare GPU算力平台隶属于UCloud,专注于提供高性价4090算力资源,配备独立IP,支持按时、按天、按月灵活计费,支持github、huggingface访问加速。 使用下方链接注册可获得20元算力金,免费体验10小时4090云算力 https://www.compshare.cn/?ytag=GPU_lovelyyoshino_LZEEKLOG_ZEEKLOG_display 最近是快到双十一了再给大家上点干货。去年我们写了一个大模型的系列,经过一年,大模型的发展已经日新月异。这一次我们来看一下使用llama.cpp这个项目,其主要解决的是推理过程中的性能问题。主要有两点优化: * llama.cpp 使用的是 C 语言写的机器学习张量库 ggml llama.cpp 提供了模型量化的工具 此项目的牛逼之处就是没有GPU也能跑LLaMA模型。llama.

Qwen3-VL与ComfyUI联动:实现AI绘画工作流自动标注

Qwen3-VL与ComfyUI联动:实现AI绘画工作流自动标注 在AI生成内容(AIGC)工具日益普及的今天,一个核心问题逐渐浮现:我们能轻松“画出”图像,但系统真的“理解”它所生成的内容吗?尤其是在Stable Diffusion等模型已经能产出高度复杂画面的当下,创作者往往面临这样的尴尬——明明输入的是“一只黑猫坐在窗台看雨”,结果却生成了“白狗趴在沙发上晒太阳”。更麻烦的是,这种偏差很难被自动发现,除非人工一张张检查。 这正是视觉-语言模型(VLM)的价值所在。而当我们将Qwen3-VL这一具备深度视觉理解能力的大模型,与ComfyUI这个以节点化著称的图像生成框架结合时,一种全新的智能创作范式便悄然成型:不仅让AI会画,还能让它“看懂”自己画了什么,并据此做出反馈、优化甚至决策。 从“生成即终点”到“可解释的生成” 传统AI绘画流程本质上是单向的:用户输入提示词 → 模型推理 → 输出图像。整个过程像一条封闭管道,缺乏对输出结果的语义感知和闭环校验。一旦生成偏离预期,只能靠经验反复调整提示词,效率低下且不可控。 而引入Qwen3-VL后,这条流程被打开了一道“认知

SendGrid高级邮件模板技巧:动态模板和个性化替换完全指南

SendGrid高级邮件模板技巧:动态模板和个性化替换完全指南 【免费下载链接】sendgrid-nodejsThe Official Twilio SendGrid Led, Community Driven Node.js API Library 项目地址: https://gitcode.com/gh_mirrors/se/sendgrid-nodejs SendGrid Node.js库是Twilio官方推出的邮件发送解决方案,提供强大的动态模板和个性化替换功能,帮助开发者轻松构建高度定制化的邮件系统。本文将分享实用的SendGrid高级邮件模板技巧,让你的邮件营销效果提升300%! 为什么选择SendGrid动态模板? 动态模板是SendGrid最强大的功能之一,它允许你创建一次模板,然后通过API动态填充内容,实现真正的个性化邮件营销。相比传统邮件发送方式,动态模板具有以下优势: * 一致性:确保品牌形象在所有邮件中保持一致 * 效率:一次创建,多次复用,减少重复工作 * 个性化:根据收件人属性动态调整内容 * 可维护性:集中管理模板,轻松更新 图:S

Stable Diffusion WebUI Docker终极指南:零基础快速部署AI绘画环境

Stable Diffusion WebUI Docker终极指南:零基础快速部署AI绘画环境 【免费下载链接】stable-diffusion-webui-dockerEasy Docker setup for Stable Diffusion with user-friendly UI 项目地址: https://gitcode.com/gh_mirrors/st/stable-diffusion-webui-docker 想要体验Stable Diffusion AI绘画的魅力,却苦于复杂的安装配置?stable-diffusion-webui-docker项目为你提供了完美解决方案!这个开源工具通过Docker容器化技术,让AI绘画环境部署变得简单快捷。在前100字内,我们已经自然融入了核心关键词:Stable Diffusion、WebUI、Docker、AI绘画环境部署。 为什么选择Docker化部署? 传统Stable Diffusion安装面临诸多挑战,而Docker化方案优势明显: 传统安装痛点Docker方案优势依赖环境复杂一键式环境配置系统兼容性差