:当AI Agent说“测试通过“时,它到底做了什么?——从“感性复核“到“理性证据链“的重构》)
系列第15篇 | 一个DB空壳引发的测试机制革命背景7月13号晚上用户问了我一个问题“你们的测试和复核是感性的还是理性的”这个问题让我愣住了。我们有test_steps表有record_step()函数有review.py检查DB记录——机制明明都在啊。但用户紧接着说“做了就是做了没做就是没做。”我查了一下DB——test_steps表里只有1条demo记录。所有真实的FIX/RETEST任务零记录。建了机制≠机制在运行。问题1DB空壳——表建了函数写了但没人调现象test_steps表结构完整CREATETABLEtest_steps(idINTEGERPRIMARYKEY,task_idTEXTNOTNULL,step_nameTEXTNOTNULL,step_typeTEXTNOTNULL,resultTEXTDEFAULTnot_done,evidence_typeTEXT,evidence_dataTEXT,executed_byTEXT,executed_atTEXT)record_step()函数能用task_db.record_step(task_idTEST-FIX-xxx,step_nameavatar_click_test,step_typetest,resultpass,evidence_typebrowser_console,executed_by小牛)review.py会检查defverify_db_audit(task_id):stepstask_db.get_steps_for_task(task_id)ifnotsteps:results.append(⚠️ 无DB执行记录警告)returnTrue,results# 降级为警告不阻塞复核原因三个层面全部断裂Agent不调用小牛测试时从未调用过record_step()——它不知道要调用review.py只警告无记录时输出⚠️但不阻塞复核照样通过没有强制约束没有任何机制阻止Agent跳过DB直接报完成整个机制是空壳。修复不能依赖Agent记得调用。必须让脚本自动完成。新建evidence_collector.py——自动采集证据的唯一入口importevidence_collectorasec# 开始会话自动清空旧记录ec.start_test_session(TEST-FIX-xxx,test,小牛)# 每步记录证据自动写DB 存文件ec.record_screenshot(TEST-FIX-xxx,avatar_after,/path/to/screenshot.png)ec.record_console(TEST-FIX-xxx,page_load,console_output)ec.record_api_call(TEST-FIX-xxx,user_api,url,200)ec.record_interaction(TEST-FIX-xxx,click_test,点击头像,弹出上传框,弹出上传框,True)# 结束会话ec.end_test_session(TEST-FIX-xxx,pass)review.py改为阻塞模式defverify_db_audit(task_id):stepstask_db.get_steps_for_task(task_id)ifnotsteps:returnFalse,[❌ 无DB执行记录 — 必须有证据链]# 阻塞# ... 检查完整性 证据文件ws_server.py增加强制检查# 小牛完成时先检查DB记录stepsdb.execute(SELECT COUNT(*) FROM test_steps WHERE task_id? AND step_type NOT IN (metadata,summary),(task_id,)).fetchone()[0]ifsteps0:# 无证据 → 自动标记失败不执行reviewdb.execute(UPDATE tasks SET review_statusfailed WHERE task_id?,(task_id,))return问题2RETEST无限循环——15层嵌套的任务名现象复核失败→自动重派RETEST→又失败→又重派…任务名越来越长RETEST-RETEST-RETEST-RETEST-RETEST-RETEST-RETEST-RETEST-TEST-FIX-0712-PC-AUTH-HEADERDB里堆了15个循环任务。原因dispatch_retest()没有重试次数限制defdispatch_retest(task_id,reason):retest_idfRETEST-{task_id}# 无限嵌套# ... 派发修复加最大重试3次defdispatch_retest(task_id,reason):retry_counttask_id.count(RETEST-)ifretry_count3:returnf⚠️ 已达最大重试次数(3次)跳过重派retest_idfRETEST-{task_id}# ...问题3RETEST通过后报告还是显示❌现象RETEST复核通过了reviewpassed但统筹报告还是显示结论❌ 共1个任务0个已通过1个复核失败原因三个bug叠加Bug 1review.py不处理RETEST前缀# 只处理TEST-FIX-xxx不处理RETEST-TEST-FIX-xxxiftask_id.startswith(TEST-FIX-):dev_idFIX-task_id[9:]else:dev_idNone# RETEST任务走到这里DEV任务没被同步Bug 2format_report.py偏移量错误# RETEST- 是7个字符不是8个innertid[8:]# 错得到 EST-FIX-xxxinnertid[7:]# 对得到 TEST-FIX-xxxBug 3FIX- 是5个字符不是4个# RETEST-TEST-FIX- 是16个字符不是17个dev_idFIX-tid[17:]# 错得到 FIX-714-AVATAR-xxxdev_idFIX-tid[16:]# 对得到 FIX-0714-AVATAR-xxx修复三处全部修正偏移量RETEST正确映射到FIX任务。经验总结1. 建了机制 ≠ 机制在运行test_steps表建了、record_step()写了、review.py检查了——但整个系统从头到尾没有任何Agent调用过record_step()。教训建完基础设施后必须验证Agent实际在调用函数、DB有真实数据才能说机制生效。2. 不能依赖Agent自觉evidence_collector.py需要Agent主动调用→Agent可以不调用。正确做法ws_server在关键节点强制检查DB记录无记录自动失败。不给Agent绕过的机会。3. RETEST前缀处理是容易忽略的边界caseRETEST-TEST-FIX-xxx需要剥两层前缀才能得到FIX-xxx。只剥一层会得到错误的dev_id导致DEV任务的review_status不被同步。4. 字符串偏移量要手动验证len(RETEST-) 7不是8。len(RETEST-TEST-FIX-) 16不是17。不要凭直觉写偏移量用len()验证。