随着 GitHub Copilot、Gemini Code Assist、Cursor 等 AI 辅助工具的普及,我们编写软件的方式正在快速变革。这些工具能够快速生成代码,自动化重复性任务,并加速功能开发。这令人兴奋且强大,但一个关键问题始终萦绕在我心头:测试。正如原文作者所说,当我们采用 AI 工具编写代码时,我们也需要改进测试代码的方式。如果 AI 能帮助我们更快地构建,那么它也应该被用来构建得更安全。因此,利用 AI 进行代码测试,保障软件质量,已经成为刻不容缓的任务。

AI 生成的代码仍然需要人为责任?

尽管 AI 能够根据学习到的模式生成代码,但它可能并不完全了解应用程序的完整上下文、特定的业务逻辑或一些奇怪的边缘情况。它可能会生成可以编译且看起来干净的代码,但我们无法保证其正确性。想象一下这样的场景:你用 AI 生成了一个处理用户订单的函数,AI 基于常见的电商模式编写了代码,但你的业务有一个特殊的规则,例如针对特定地区的用户有不同的折扣计算方式。如果 AI 没有学习到这个规则,或者你没有明确告知 AI 这个特殊情况,那么生成的代码就会在特定场景下出错。

这就是为什么 测试 比以往任何时候都重要。它们是确保代码实际按预期工作所必需的安全网。如果没有 测试,我们可能只是在信任一个黑盒。我自己也意识到,大多数时候,我们倾向于快速提交 AI 生成的代码,而不是逐行审查。例如,我在使用 Copilot 生成一个数据处理脚本时,Copilot 快速生成了看似完美的 Pandas 代码,但在处理缺失值时,默认行为直接导致了程序崩溃。如果没有充分的 测试,这个 bug 可能会隐藏很久,直到生产环境出现问题。

利用 AI 编写测试

我们经常使用 AI 来生成函数或重构代码,但却止步于要求它编写 测试,这感觉就像错过了一个机会。现代 AI 工具能够通过简单的提示生成完整的 测试 套件,例如:

  • “为这个函数编写单元 测试,包括边缘情况和失败场景”
  • “创建外部 API 的请求模拟,包括超时场景、权限错误或格式错误的输入案例”

如果它们能够遵循团队的 测试 和编码结构,那就更好了。与其将 测试 视为可选项,不如将其视为功能的后半部分。例如,你可以要求 AI 为一个用户注册接口编写 测试,包括以下内容:

  • 正常注册流程的 测试
  • 用户名已存在时的 测试
  • 密码强度不足时的 测试
  • 验证码错误时的 测试
  • 网络超时时的 测试

通过充分利用 AI 的能力,我们可以更加高效地完成 测试 任务,提高代码的健壮性。

利用 AI 生成更好的测试数据

考虑一个常见的例子:图像识别功能。测试 这样的系统需要各种各样的图像来覆盖不同的光照条件、模糊、部分对象等。传统上,收集这些多种数据集既耗时又需要大量资源。例如,在开发一个自动驾驶系统的图像识别模块时,我们需要收集各种场景下的图像数据,包括白天、夜晚、雨天、雾天等。传统的做法是,我们需要派出专业的团队,花费大量的时间和精力,才能收集到足够的数据。

现在,借助生成式 AI,我们可以在几秒钟内创建数百个涵盖各种真实世界场景的合成图像。这些图像可以涵盖成功和失败案例,测试 系统如何处理夜间拍摄的照片、带有运动模糊的照片或具有严重遮挡的照片等等。我们可以轻松地按需生成它们!这种数据集多样性过去是一个瓶颈,而 AI 可以用来消除这种障碍。举个例子,OpenAI 的 DALL-E 3 或 Midjourney 等 AI 图像生成工具可以根据你的需求生成各种各样的图像数据,从而大大降低了 测试 成本和时间。

建立测试的 Prompt 指南

在使用 AI 时,一件有帮助的事情是设置清晰的 Prompt 模式。团队中的开发人员应该知道在向 AI 工具请求代码时应该包含什么。这可以包括实现和 测试,甚至包括 测试 文件的命名约定,以包括边缘情况和无效输入的说明。例如,你可以为团队创建一个 Prompt 指南,其中包含以下内容:

  • 明确描述要测试的功能: 提供清晰的功能描述,包括输入、输出和预期的行为。
  • 指定测试类型: 指明你希望 AI 生成的 测试 类型,例如单元 测试、集成 测试 或端到端 测试
  • 提供代码片段: 提供要 测试 的代码片段,以便 AI 更好地理解上下文。
  • 包含边缘情况和异常处理: 指示 AI 考虑边缘情况和异常处理,例如无效输入、空值或超时。
  • 指定测试框架和库: 告知 AI 你使用的 测试 框架和库,例如 JUnit、pytest 或 Mocha。
  • 定义测试标准: 说明 测试 应该满足的标准,例如代码覆盖率、性能或安全性。

此外,当开发人员使用不同的 AI 工具或风格时,一致性非常重要,否则会导致代码库混乱。共享的 Prompt 指南有助于保持每个人的一致性。例如,如果团队统一使用 pytest 作为 测试 框架,并要求 AI 生成的 测试 代码都符合特定的代码风格,那么就可以避免因为 AI 生成的代码风格不一致而导致的代码维护问题。

以下是一个 Prompt 指南的示例:

**Prompt 指南:AI 代码测试**

**目标:**  确保使用 AI 生成的代码经过充分测试,并符合团队的代码质量标准。

**通用原则:**

*   **清晰性:** 明确说明需要测试的功能,并提供足够的上下文信息。
*   **完整性:** 涵盖所有可能的场景,包括正常情况、边缘情况和异常情况。
*   **一致性:**  遵循团队的代码风格指南和测试标准。
*   **可维护性:**  编写易于理解和维护的测试代码。

**Prompt 模板:**

为 [功能名称] 编写 [测试类型] 测试。

功能描述:[功能描述,包括输入、输出和预期行为]

代码片段:
[代码片段]

测试类型:[单元测试、集成测试、端到端测试]

测试框架:[JUnit、pytest、Mocha 等]

测试标准:

  • 代码覆盖率:[例如,达到 80% 的代码覆盖率]
  • 性能:[例如,测试用例执行时间小于 100ms]
  • 安全性:[例如,防止 SQL 注入、XSS 攻击等]

边缘情况和异常处理:

  • [例如,输入为空值时的测试]
  • [例如,输入无效值时的测试]
  • [例如,网络超时时的测试]

其他要求:

  • [例如,遵循特定的命名规范]
  • [例如,使用特定的 Mocking 库]
**示例:**

为用户注册接口编写单元测试。

功能描述:用户可以通过 API 注册,需要提供用户名、密码和电子邮件地址。API 会验证用户名是否已存在,密码强度是否足够,并发送验证邮件。

代码片段:

def register_user(username, password, email):
    # ... 用户注册逻辑 ...

测试类型:单元测试

测试框架:pytest

测试标准:

  • 代码覆盖率:达到 90% 的代码覆盖率
  • 密码强度:密码必须包含大小写字母、数字和特殊字符,长度至少为 8 位

边缘情况和异常处理:

  • 用户名已存在时的测试
  • 密码强度不足时的测试
  • 电子邮件地址格式错误时的测试
  • 数据库连接失败时的测试

其他要求:

  • 使用 pytest-mock 库进行 Mocking
**提示:**

*   根据具体情况调整 Prompt 模板。
*   提供尽可能多的信息,以帮助 AI 生成更准确的测试代码。
*   审查 AI 生成的测试代码,确保其符合预期。

通过建立清晰的 Prompt 指南,可以提高团队在使用 AI 进行 代码测试 时的效率和一致性,从而提升代码质量。

结论

AI 在开发中不再是未来的概念。它是我们日常工作的一部分。但是,虽然 AI 可以加速开发,但质量仍然是人为责任。质量是不可妥协的底线,尤其是在软件开发领域。每一个疏忽都可能导致严重的后果,从用户体验下降到安全漏洞的出现。因此,我们必须将质量意识融入到开发的每一个环节,从需求分析、设计、编码到测试和发布,都要严格把控。只有这样,我们才能构建出真正可靠和有价值的软件产品。

下次使用 AI 生成代码时,请记住进行全面的 测试。更快的速度固然重要,但只有当我们信任我们所构建的内容时,它才有意义!AI 是工具,人是主导。我们应该将 AI 视为助手,而不是替代品。只有当我们充分发挥人的智慧和创造力,并借助 AI 的强大能力,才能真正实现软件开发的飞跃。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注