每一次端到端测试运行都有成本,而这个成本是以反馈循环中的分钟数来计算的。
经典场景:有人重构时改了一个 data-test 属性,不知十个用例引用了它。理想情况,一次 15 分钟的合并前检查在快结束时失败告警。最糟情况,改名悄悄并入,凌晨 3:30 夜间构建挂掉。第二天上午,有人得花一个小时才弄明白,这次“失败”不是 bug、不是宕机、不是偶发不稳定,只是三天前被改掉的选择器名字。
无论哪种情况,你都在用分钟甚至小时级的测试执行时间,去获取一个本可在启动浏览器前、一秒内就能知晓的信息。
我们团队决定不再交这笔时间税了。
我们的解决方案是一个大约 500 行的 Node 脚本。它会将我们所有测试用例引用的每一个选择器,与应用源代码中能够生成的每一个选择器进行交叉校验,然后在大约一秒钟内让触发了这个问题的 PR 直接失败。整个过程没有浏览器启动,没有应用引导,也没有 AI 参与。我们是为自己的 Cypress 测试套件打造的,前端技术栈是 Vue 3,大约有 200 个测试文件,约 6300 个选择器调用点。但这个思路跟 Cypress 本身关系不大,它同样适用于 Playwright、WebdriverIO 或其他任何框架,因为被检查的对象不是测试框架本身,而是一个命名的契约。
更棒的是:当它首次在我们那套全部绿灯通过的测试套件上运行时,它直接揪出了 8 个真实的自动化缺陷。
一个像 cy.getByDataTest('orders-table') 这样的选择器,本质上是对一个在别处定义的元素的引用,就像一次函数调用。当有人删掉那个函数时,编译器会立刻告诉你。但反过来,当有人删掉一个属性时,工具链却一声不吭,你只能等到某个恰好触及那个元素的测试恰好运行时,才能发现出了问题。
在讨论这个问题的过程中,我们明确地排除了运行时的“自愈”选择器方案,也就是那种依靠 AI 去猜测你可能想指向哪个元素的做法。我们相信自愈技术在某些场景下是有用的,但它通常会掩盖掉选择器漂移的问题。所以我们追求的是恰恰相反的效果:让导致漂移的 PR 直接失败,以一种清晰且确定性的方式。我们希望按照自己的理解去发现问题并修复它。
这种静态检查之所以能实现,完全依赖于我们此前已强制推行的一项约定:每个测试用例中的每一次元素访问,都必须通过一个统一的辅助调用 cy.getByDataTest('...') 来完成。这实际上是我们测试框架选择器调用之上的一个单行封装。而在应用端,所有组件都只暴露一个 data-test 属性作为测试的锚点。没有原始的 CSS 选择器,没有 XPath,也没有文本匹配来做元素定位。
如果你的测试套件在选择元素时是临时拼凑的,一会儿用 CSS 类名,一会儿用测试 ID,一会儿又靠文本内容,那根本不存在一个可供检查的契约。这套约定本身就是这个契约,而脚本只是负责强制执行它。如果你还没有建立起这种开发纪律,那么采纳它就是解决问题的第零步,而且即便你永远不打算构建这个检查器,这一步本身也回报丰厚。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.