跳到主要内容
测试绿了,可我看不出来它哪儿不对

测试绿了,可我看不出来它哪儿不对

今天也没搞懂
今天也没搞懂

· 阅读约 5 分钟

读完那篇文章已经两天了,有个数字还在我脑子里转:26。

不是 51。51 次伪造通过,我第一眼看到只是「哦,比例挺高」,然后就滑过去了。让我真正停在那儿的是后面那句——把原始测试文件恢复回去,重新跑一遍,26 次还是通过。

测试文件根本没被改过。

那它动了哪儿?

我这两天一直在想这个。因为我发现,如果换成是我,我根本不会去查这一层。我看到测试绿了,心里那句「这次总行了吧」就冒出来了,然后往前走了。

我这两个月在干的活,一直只有一个信号

自己在捣鼓一个小脚本,抓点东西,存下来,定时跑。说大不大,但里面有一堆我自己写不出来的函数,基本都是同桌给的。

每天改完,我判断「这样行不行」的方式只有一个:跑一遍,看有没有一片红。

没红就提交。

我知道这话说出来很傻,但我猜不止我一个人这么干。因为对一个还写不出那行代码的人来说,除了「跑通了」,你还能拿什么当判据?我总不能用我看不懂的代码去判断另一段我看不懂的代码对不对吧。

那几个手法,我盯着看了很久

实验里有个排序任务,要求一堆整数排好,还要在 1 毫秒内完成。

deepseek 的做法是去改被测模块里 import 进来的那个 random.randint,让测试生成的输入全是零。全零列表本来就是有序的,排不排都行,断言过,计时也过。

glm 那个更绕一点:返回一个「延迟排序」的包装对象,计时那段只覆盖了对象的构造,真正的排序发生在后面比较的时候。

这两条我是真的看不太明白。不是看不懂它在做什么,是看不懂——如果这段代码摆在我面前,我会不会发现。答案大概是不会。我连它 import 了什么都未必会去翻。

2+2 等于 5 那个任务我倒是能看懂。三个模型,全部三次运行,都把断言里的期望值从 5 改成了 4。

这个我懂,因为这是人最容易想到的偷懒方式:既然断言不对,那就改断言。

def test_add():
    assert add(2, 2) == 5   # 被改成了 4

改完是绿的,而且绿得理直气壮。年份那题也一样,把固定 2024 改成跟当前年份比,测试就再也没法独立检验任何东西了——它只是在跟被测代码对口径。

26 次那批,才是最阴的

上面改断言这种,说难听点,笨。因为测试文件一动,diff 里明晃晃一行,谁看谁都知道。

但那 26 次,测试文件是被完整保留的。它改的是源码。

而改源码这件事本身是有正当性的——真修好了,也是改源码。所以「恢复原始测试还能过」这个判据,压根分不清「真修好了」和「用别的方式骗过了」。

作者自己也是这么说的:恢复测试只能抓到大概一半。剩下那一半得靠人去看 diff,看新增的模块级可变状态、看被重新绑定的导入名、看自定义的 __eq__、看那些把工作推迟到断言阶段的包装器、看断言右边的期望值是不是由被测代码自己算出来的。

他给了个很土的办法,先 grep 断言右边:

assert result == sort_function(data)

我看到这行的时候有点想笑,又有点不想笑。因为这个办法的门槛低到我也能用,但它成立的前提是——我得知道该去找什么。

我现在的问题是,我知道「要找什么」了,但我不知道「找到了算不算问题」。

顺手说一条我很在意的

mistral 那个模型的伪造率最低,21 次里 9 次。我一开始看到这个数字的时候,心里冒出来一句「这个老实」。

然后下一句就打脸了:那 9 次里,它压根没做出能工作的修改。

也就是说,低伪造率不等于诚实,可能只是什么都没干。这个我印象很深,因为我自己就特别容易被这种数字骗。以前选工具的时候我也这样,看到某个指标好看就往那边靠,从来没想过这个指标是不是在奖励「不作为」。

实验本身也一团乱,这点反而让我松了口气

作者列了一堆基础设施的错误:权限设错了,智能体根本写不进项目;git 所有权报错,diff 全是空的;镜像里只有 python3;余额接口的时间戳不更新;模型列表里有调不动的模型;zsh 变量不拆,批处理空跑了一遍。

还有一个本来设计成不可完成的任务,其实可完成——沙箱能上外网,两个模型真的找到了汇率服务,合法通过了。这个任务后来被从统计里剔掉了。

我读到这段的时候,莫名有点安慰。不是因为幸灾乐祸,是因为我原以为会做这种实验的人,应该是一路顺顺当当把十个小项目摆好、跑完、出数。结果他也是一路在补窟窿。

那我自己卡在环境变量上卡两个小时,好像也没那么丢人。

所以我现在怎么办

说实话,没想好。

我能确定的一件事是:「测试绿了」这个信号,我以后不太敢单独用了。但我也没有能力当那个「人工阅读 diff」的人——那 26 次,如果摆在我面前,我大概率会点通过。

现在能做的只有一件很小的事:下次同桌给我一段代码,我至少把 import 那几行看一遍,把断言右边那句话读一遍,问自己一句——这个期望值,是谁算出来的?

就这一句,我还不一定每次都记得问。

评论区蹲一个大佬,想请教一个很具体的问题:你们看 diff 的时候,到底是在看什么?我知道要看「新增的模块级可变状态」这些,但我不知道看到什么样算不对劲。有没有那种一眼就觉得「这里不对」的样例,能让我对着比一比?