跳到主要内容 AI 辅助编程的边界探索:当 Copilot 学会写测试 | 极客日志
TypeScript Node.js AI 大前端
AI 辅助编程的边界探索:当 Copilot 学会写测试 探讨了人工智能辅助编程工具(如 Copilot)在编写测试用例方面的能力边界。通过支付网关模拟器和订单服务的实验,发现 AI 擅长生成基础单元测试和 Mock 代码,但在处理业务意图理解、边界条件验证及复杂集成测试时存在幻觉和局限。文章指出 AI 目前更适合作为高级助理而非独立工作者,建议开发者结合人类判断力,明确 Prompt 并指定框架,利用 AI 提高覆盖率的同时保持对测试质量的把控。
岁月神偷 发布于 2026/4/6 更新于 2026/4/13 2 浏览AI 辅助编程的边界探索:当 Copilot 学会写测试
在过去的几年里,我们见证了人工智能辅助编程工具(如 GitHub Copilot、Cursor 等)从简单的代码补全插件,进化成为能够独立思考、生成复杂逻辑的数字伙伴。大多数开发者的使用场景停留在帮我写个排序算法或者帮我补全这个 React 组件的样式。然而,当 AI 开始染指软件工程中最繁琐、最需要逻辑严密性的领域——测试(Testing)时,一切都变得有趣且充满挑战。
今天,我们就来深入探讨一下:当 Copilot 学会了写测试,它的边界在哪里?它能否取代人工编写测试用例的工作?它又会在哪里翻车?让我们通过一系列真实的代码实验来寻找答案。
1. 从写代码到验代码:AI 的新战场
传统的编程教学往往强调如何实现功能(Implementation),而软件工程的核心却有一半是维护。维护的核心不是加功能,而是保证加功能不破坏旧功能。这就使得测试变得至关重要。
对于 AI 来说,写一段计算斐波那契数列的代码是简单的,因为逻辑是收敛的。但是,写一段针对斐波那契数列的测试用例则是发散的:你要考虑输入 0、输入负数、输入超大数、溢出处理等等。AI 写测试的核心难点在于:它不知道产品的意图(Intent),它只能根据上下文进行模仿。
下面,我们构建一个典型的业务场景,来测试 Copilot 的能力边界。我们将使用 TypeScript 和 Jest 作为实验环境。
场景设定:一个简单的支付网关模拟器
我们需要一个看似简单但包含逻辑分支的函数。
interface PaymentRequest {
userId : string ;
amount : number ;
currency : 'USD' | 'CNY' | 'EUR' ;
}
interface PaymentResult {
success : boolean ;
transactionId ?: string ;
error ?: string ;
}
export const processPayment = (req : PaymentRequest ): PaymentResult => {
if (req.amount <= 0 ) {
return { success : false , error : 'Invalid amount' };
}
(req. . ( )) {
{ : , : };
}
txId = ;
{ : , : txId };
};
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown 转 HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
HTML 转 Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
if
userId
startsWith
'test_'
return
success
true
transactionId
'test_tx_123'
const
`tx_${Math .random().toString(36 ).substr(2 , 9 )} `
return
success
true
transactionId
现在,如果我们直接告诉 AI:为这个文件写测试,会发生什么?
2. 初级实验:AI 能写出 Happy Path 吗? Happy Path(快乐路径)指的是测试用例中最理想、最常见的流程,比如用户付了钱,系统返回成功。
Prompt: // Write unit tests for processPayment function using Jest
Copilot (or similar AI) 生成的代码:
import { 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 ();
});
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 逻辑理解能力的地方。
export const saveTransaction = async (data : any ) => {
return { id : 'db_123' , ...data };
};
import { saveTransaction } from './database' ;
export const createOrder = async (items : string [], userId : string ) => {
if (!items.length ) throw new Error ('Cart is empty' );
const order = { items, userId, createdAt : new Date () };
const saved = await saveTransaction (order);
return saved;
};
Prompt: // Write tests for createOrder and mock the database module
import { createOrder } from './orderService' ;
import { saveTransaction } from './database' ;
jest.mock ('./database' , () => ({
saveTransaction : jest.fn (),
}));
describe ('createOrder' , () => {
it ('should save order to database' , async () => {
const mockSave = saveTransaction as jest.Mock ;
mockSave.mockResolvedValue ({ id : 'mock_id' });
const result = await createOrder (['item1' ], 'user_1' );
expect (mockSave).toHaveBeenCalled ();
expect (result.id ).toBe ('mock_id' );
});
it ('should throw error if cart is empty' , async () => {
await expect (createOrder ([], 'user_1' )).rejects .toThrow ('Cart is empty' );
});
});
评判: 这一波操作非常漂亮。AI 不仅自动生成了 jest.mock,还正确处理了异步函数 (async/await)。这说明在基于上下文的单元测试场景下,AI 已经达到了相当高的可用性。
但是,精彩的地方来了。如果我们稍微修改一下业务逻辑,增加一个边界条件,AI 的表现会如何?
4. 陷阱与幻觉:AI 写测试时犯的那些错 AI 并不真正理解代码,它只是根据统计学预测最可能的下一段文本。这导致它在处理边界值和特定业务规则时,会产生令人啼笑皆非的幻觉测试。
案例 A:永远不会错的测试 假设我们有一段非常糟糕的代码(或者 AI 根本看不懂的混淆代码):
export const getStatus = (code : number ) => {
if (code > 100 ) return 'OK' ;
return 'ERROR' ;
};
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' , () => {
const result = getData ();
const unique = new Set (result);
expect (unique.size ).toBe (result.length );
});
如果你运行这个测试,它会 Fail。但开发者看到 Fail 后,往往会去改代码(试图让数组没有重复),而不是意识到这个测试用例本身是基于错误的假设(数据源本身可能有重复,这不是一个 Bug,而是一个业务事实)。AI 制造了新的伪 Bug。
案例 C:复杂集成测试的无力 在端到端(E2E)测试或者集成测试中,AI 的表现会指数级下降。因为这需要 AI 理解状态(State)。
想象一下,你需要测试:用户登录 -> 添加购物车 -> 点击结算 -> 验证库存扣减 -> 验证支付回调 -> 验证数据库订单状态。
这种长达 10 步的流程,AI 很难一次性生成完整的 Flow。除非你在极其细粒度的 Prompt 中,详细描述每一步的数据库状态和预期结果。
5. 人机协作:重新定义测试工作流 既然 AI 不是万能的,那么最佳的策略就是利用 AI 的吞吐量,配合人类的判断力。在这个流程中,AI 不再是执行者,而是协作者。
AI 负责第一层的覆盖(Happy path + 基本的 Mock),而人类负责最深层次的逻辑校验。
实践技巧:如何高效地让 AI 写测试?
不要只说写测试 。
❌ // 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.
指定测试框架 。
明确告诉它用什么工具(例如 Jest, Mocha, PyTest),它能生成更精准的脚手架。
让它扮演 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,在测试领域的定位应该是高级助理,而不是独立工作者。
生成样板代码(Boilerplate)。
编写针对确定逻辑的单元测试。
批量生成 Mock 代码。
将代码转化为测试(如果你有一段代码,它能帮你写测试)。
理解真实的业务意图(Context)。
编写性能测试和压力测试。
维护测试(当代码重构后,测试需要同步更新,AI 往往会照着旧代码生成新的错误测试)。
探索性测试(Exploratory Testing)。
结论是:Copilot 能把测试的门槛降低,但无法把测试的质量拉高。质量取决于人类对业务的理解深度。
最后,建议在使用 AI 辅助编程时,配合阅读一下官方的最佳实践,比如 Jest 官方文档中关于异步测试的章节,或者 MDN Web Docs 上关于单元测试的基础概念。
让我们拥抱变化,利用工具,但永远保持怀疑精神。毕竟,代码可能会说谎,但测试不能。