测试生成技术成熟了吗?

2025-03-27   出处: everydayunittesting.com  作/译者:Camille/小窝

让我们聊聊测试生成技术。因为无论是ChatGPT、Copilot还是其他工具,它们都能在眨眼间生成大量的测试用例。但总有人要来泼泼冷水。

我见证过各类测试生成技术超过20年的发展。是的,20年前,我还在钻研代码的时候,就已经有工具能根据我写的代码生成测试用例了。墙上(这里指界面啦)就已经有了一个按钮,点击它就能基于我写在 “墙上”(代码编辑区域)的代码创建一个测试用例。虽然有点原始,但它确实有效。

在过去,我使用的是 Visual Studio(黑白界面版本),当我右键点击一个方法时,会出现这样的选项:

好吧,我放的这张图片稍微现代了点,而且是彩色的。但这个功能现在依然存在。

当时,这个工具并不是一个非常智能的向导(还记得那些向导吧?)。我右键点击一个方法,它会根据我要测试的方法签名生成一个测试用例,名字叫…… 你猜怎么着……

“AddTest”。真是天才。

生成的测试代码只是创建了一个类的实例,并调用了该方法。就是这样。显然,你还得添加你真正想传入函数的参数。


这种类型的测试生成有两层含义。首先,有时生成的测试甚至无法编译(你需要提供更好的输入,甚至可能需要自己手动调用方法)。其次,如果编译成功,它通常会失败。

看到那个 Assert.Fail()​ 吗?是的,我知道这是故意的,但你想从一个生成的测试用例中期待什么呢?

另一种选择(没有假设的失败,也去掉了 assert​)是,测试几乎总是会通过。这就是没有断言的测试的表现。你需要自己添加这些断言。

好了,这显然不是很好的测试。根据生成的结果,我通常会跳过生成过程,自己编写测试用例。对我来说,另一个问题是,测试用例生成无法与TDD(测试驱动开发)兼容。你知道的,测试优先?你无法为不存在的代码生成测试用例。

API时代
这种集成开发环境IDE能力(微软并不是唯一一个拥有代码生成魔法的公司),至少在单元测试领域,并没有发生太大变化。那是,我们已经非常热衷于使用 API 了,测试生成也与时俱进。现在我们可以为API调用生成测试用例。

当然,也有一些注意事项。

现在,我们不再是生成一个“测试用例”,而是生成一个“请求”。不再是单纯的 “生成”,而是编辑参数,填写空白,发送请求并记录请求与响应。想象一下像 Postman 这样的 UI 工具,它不仅能做这些,还能根据你需要的语言为你生成包装代码。不用想象,它确实能做到。

这还不够完善。我还是得像之前给 “AddTest” 重命名一样,给请求重命名。而且,即使我不修改生成的代码(实际上我肯定会重命名一些东西的),就算测试记录了所有的输入和输出,它仍然面临一个问题:预期结果是什么呢?

仅仅是200状态吗?整个响应体吗?也许是其中的某些部分,而不是后端自动生成的ID?那头信息呢?

真是麻烦! 这时我又得插手了。告诉测试环境什么对我来说是重要的。根据工具的不同,这可能需要大幅补充内容、做些修改,或者干脆从头重写。

UI测试生成时代的故事
接着我们进入了UI时代。现在我们有了针对 UI(Web 或移动端)的测试生成器,它能根据你的框架和技术栈生成测试代码,记录你的工作流程,并允许你直接从生成器中创建断言。


顺便说一下,这是 Playwright 的 Web 录制器。

Gil,这对你来说够好了吧?看,这才是真正的魔法!
好吧,不完全是。你看,这个工具确实能找到元素,但它的方式并不是我希望在测试中使用的方式。你看到图片了吗?它定位到了文本框,但它建议通过占位符来定位它(看那个提示框),生成的测试代码也是这样写的。

这真的是定位文本框的正确方法吗?我会这样写吗?我的意思是,为什么不通过它的标签来定位呢?下一个看这个测试代码的人难道不会想——为什么Gil这样写?

是的,他们会的。我不能让这种事情发生。

生成一次,维护终身
那么,维护性怎么样呢?这些测试很容易写,但它们可读吗?
让我们看看为这个UI生成的测试。(这其实是一个非常小、简单的例子,取自我的Playwright网络研讨会)。

看看所有的重复代码。看看所有的硬编码值。仔细看看。

现在,我们迎来了由人工智能生成的测试用例。它们似乎更了解代码的功能。它们 “理解” 代码。所以生成的测试用例应该更好,命名也更好。我什么都不用做了!

不,我还是不喜欢这些结果。这些测试用例永远都不是我想要的写法。

好了,先不吐槽了。我相信这些问题随着时间的推移会有所改进。我真心希望如此。

并不是我不喜欢工具,我真的很喜欢。我只是觉得工具是为了某种目的而设计的,而不幸的是,我们,作为用户,往往有不止一个目标。

当然,我们希望能节省写测试用例的时间。要是能找到一种方法,不用写这些讨厌的测试用例就能编写出高质量、能正常运行的代码,我们肯定会用的。但我们还是离不开这些测试用例。所以我们得编写它们。而测试生成器就是用来生成测试用例的。

但我们还有一个期望——当测试失败时,我们希望能确切地理解测试用例想要做什么,这样我们才能找到问题所在。而在可读性和可维护性方面(这涉及到真正的人来参与),正是我们这些自动化工具的不足之处。

测试生成工具缺乏的是上下文。在它们看来,只有接口,而其他的就交给测试编写者去做。编写者需要构建正确的输入,指定正确的预期结果。他们需要解释不同用例之间的区别,哪些是共享的设置,而且命名也非常重要。

由于这些工具无法理解应用程序或业务流程,当然,也无法理解人类开发者,因此测试用例生成工具在这一点上卡住了,把剩下的工作留给了作者。

如果我们能够直接从它们停止的地方继续,那会很好。那些帮助你走一半甚至三分之一的工具很棒。但是如果我们需要替换掉生成代码的一半,这不仅仅是浪费,简直是令人烦恼的。

未来展望
并不是说我们没有在进步。一些AI工具可以分析被测试的代码,并尝试为测试提出一个可能的场景。它们对上下文的“理解”依赖于代码,甚至更多的是系统本身。它们“理解”代码的程度越高,生成的测试用例就越有用。

为小段代码生成测试用例还比较容易(好吧,也不是那么容易,但相对而言)。但要理解大型系统中的工作流程,这可是个大问题。不幸的是,我们还没有达到那个水平,这从生成的测试用例中就能看出来。

让我们实话实说——仅凭代码来理解软件是非常困难的。哪些路径重要?哪些部分将被更频繁地使用?你需要很多上下文来创建正确的测试用例。别忘了——“代码之外”的事情呢?或者用专业点的话说 —— 如果测试生成器为了理解代码只知道我的代码仓库,而调用的或被调用的代码在另一个仓库里,那么它的理解水平就会降低。测试将无法反映实际情况。

但它们会通过。并给我们虚假的信心。

在一段时间内,我还是会持怀疑态度,自己写测试用例。当然,我会利用工具来稍微加快进度,但完全依赖自动生成的测试用例?

至少现在还不会。

如果你想自己写测试用例(你确实应该这么做),看看我的单元测试和TDD研讨会。你会在那里学到很多东西的!


声明:本文为本站编辑转载,文章版权归原作者所有。文章内容为作者个人观点,本站只提供转载参考(依行业惯例严格标明出处和作译者),目的在于传递更多专业信息,普惠测试相关从业者,开源分享,推动行业交流和进步。 如涉及作品内容、版权和其它问题,请原作者及时与本站联系(QQ:1017718740),我们将第一时间进行处理。本站拥有对此声明的最终解释权!欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,与我们的编辑和其他窝友交流。
/73 人阅读/0 条评论 发表评论

登录 后发表评论
最新文章