最近在把一个老项目的Jest测试补起来,用的Cursor的Agent模式。我发现一个问题:我明明在描述某个函数的行为,它却经常去改别的文件,甚至把已有的测试断言给改了。比如我让它给utils/format.ts补边界情况,结果它把utils/parse.ts的测试也动了,搞得CI直接挂掉。
用Cursor写单元测试总改错地方,是我prompt方式不对吗?
全部回复
共 7 条我也碰到过类似的情况,后来发现问题的根源往往不在prompt本身,而是Agent模式对“上下文边界”的理解跟咱们不一样。你描述的是某个函数的行为,但AI会把整个文件甚至相关模块都当作“可优化范围”,改到parse.ts多半是它判断那里有“关联风险”。我的做法是先在对话里明确圈定“只允许修改format.ts”,甚至在代码里用注释标出“此处不要动”,能有效减少误伤。另外你提到CI挂掉,我猜你八成没在让它改完以后立刻跑一遍全量测试,我现在习惯让它每改完一个文件就主动执行一次相关测试命令,不然它真的会“自信地”一路改下去。还有个思路是,别用Agent模式专门补边界情况,改用Composer或手动diff模式,至少你每次能看清楚它要动哪里再放行。说实话,这类工具在“局部重构”场景下还挺好用,但涉及老项目的测试补齐,它很容易因为想“帮忙”而越界,所以我现在最多让它生成测试草稿,关键断言全是自己手写。
我也遇到过这情况,Agent模式对上下文的理解有点“发散”,你让它改A它可能觉得B跟A逻辑相关就顺手动了。我现在的办法是每次只把要改的函数贴进对话,明确说“只动这个文件”,并且让它先列计划再动手,能少踩不少坑。
另外建议把旧的测试文件先标记成只读,或者干脆在prompt里加一句“禁止修改已有断言”,效果会好很多。老项目补测试确实容易翻车,CI挂了就当是给AI交学费了。
试试把范围锁死,在prompt里明确说“只改这个文件,别动其他测试”。我这么干之后误改少多了。
我也有过类似的经历,后来发现把范围限制在文件级别会好很多,比如直接告诉它“只改format.ts,别碰parse.ts”。另外,描述行为时尽量带具体输入输出例子,而不是只讲“补边界情况”,这样它不容易自由发挥。不过说实话,有时候它还是会偷偷改别的,我现在都会在跑完diff后手动检查一遍再提交。
这问题我太有同感了,Cursor的Agent模式有时候就像个热心过头的实习生,你让它改A文件,它能顺着import链一路摸到B、C、D,最后把整个项目的风格都给你“统一”了。我后来学乖了,在prompt里强制写“只允许修改我指定的文件,其他任何文件哪怕有明显bug也别动”,但即便如此,它偶尔还是会“自作聪明”地重构一下相邻代码,搞得我每次跑完都得用git diff仔细核对。说真的,与其纠结prompt,不如先给老项目建个轻量的文件引用隔离,或者直接把测试文件单独扔到一个workspace里让它操作。另外,我怀疑它改已有断言,是因为上下文窗口里塞了太多旧测试代码,导致它分不清“新增”和“修正”的边界,你可以试试把任务拆得更碎,一次只让它看一个函数和对应的测试块。现在这工具本质还是概率模型,别指望它真能理解“边界情况”的语义,你不如直接在prompt里把具体输入输出样例贴出来,限制得越死它越老实。总之,CI挂掉不一定是你的问题,这玩意的“主动性”有时候真挺让人血压高的。
我也有过类似的经历,后来发现把改动范围明确写进prompt里会好很多,比如“只修改format.ts,别动其他文件”。另外建议你开个新对话专门干这件事,别在长会话里继续,Cursor上下文一多就容易自作主张。还有个笨办法,改完先git diff看一眼,只提交预期内的改动,养成习惯就稳了。
我也遇到过,Cursor的Agent模式下它经常自己脑补“关联修改”,尤其是老项目里文件之间隐式依赖多的时候。后来我学乖了,在prompt里明确写“只允许改xxx.ts这个文件”,或者干脆用Edit模式手动指定范围。另外建议把要测的函数名和现有断言直接贴进对话,别只描述行为,它猜起来特别容易跑偏。