使用ChatGPT提示能自动编写测试代码吗?- michaelfeathers


如今,有许多基于GPT的工具可以分析注释和代码,并在您键入时提出补全建议。
您也可以提示它们生成或转换代码。

无论哪种情况,您都可以选择接受更改(或不接受),但必须小心。

基于GPT的工具容易产生幻觉问题--它们是不确定的。
它们用于生成创造性输出。
但是 "被卡住 "的随机性可能会导致过多的创造性:导致生成的代码出现微妙的错误或与您的意图不符。

在最近的一次会议上,一位发言人建议使用人工智能来处理开发人员不喜欢的任务,例如编写单元测试,这让我大吃一惊。

这个建议让我大吃一惊,因为它忽略了与GPT工作方式相关的内在不确定性。

让人工智能工具为我们的代码编写正确性测试似乎是个好主意,但我们怎么知道这些测试是否检查了我们想要的行为呢?
当我们使用人工智能生成它正在测试的代码时,情况就更糟了。
生成的代码的行为可能与我们的意图不同,而它生成的测试可能错误地将这些差异解释为正确的行为。

让我们详细探究。

传统流程
以下是使用当今人工智能工具的自然工作流程:

  • 提示工具为您生成一个方法(或者开始输入,然后让工具完成)。
  • 检查生成的代码(因为它可能不是你想要的)。
  • 提示工具为您编写测试。
  • 检查生成的测试(因为它们也可能没有检查你想要的行为)。

审查步骤之所以存在,是因为该工具增加了流程的不确定性。
这对我们来说是额外的工作。
更糟糕的是,当我们使用一个不确定性来检查另一个不确定性时,我们可能会在审查中遗漏任何错误。

我们如何才能摆脱这种情况,实现更好的工作流程?

我们可以做的一件事就是寻找杠杆。是否有办法利用我们正在做的事情来控制不确定性?

有。

我们可以将提示写成测试。
它们既可以作为工具的输入,也可以作为工具输出的检查。

下面是一个例子,我写了一个测试来开始一个小的待办事项列表应用程序的工作:

@Test
public void renderSessionWithOneTask() {
    Session session = new Session();
    session.add(new Task("task 1"));

    assertEquals(
" 0: task 1\n”, session.render());
}


然后,我将测试作为我的提示的一部分,并要求工具编写代码来满足它。

它做到了。我运行了测试,测试通过了。

接下来,我添加了另一个测试:

@Test
public void renderSessionWithSeveralTasks() {
    Session session = new Session();
    session.add(new Task("task 1"));
    session.add(new Task(
"task 2"));
    session.add(new Task(
"task 3"));

    assertEquals(
" 0: task 1\n 1: task 2\n 2: task 3\n", session.render());
}

当我提示该工具修改代码以满足两个测试时,它完成了工作,测试通过了。

有时生成的代码不能通过测试。有时,它通过了测试,但它的设计方向我不同意。

没关系,我在提示中使用测试作为检查工具输出的一种方式。
如果工具没有通过测试,我可以让它再试一次,或者我可以手工编写代码来满足我想要的提示。

读到这里的很多人可能会认为这个过程是测试驱动开发的一种变体
的确如此,但它也是测试驱动开发的一种概括。

当我们编写提示时,我们可以通过使用它们作为工具输出的自动检查,将它们提升到生成过程之上。

请注意,我在使用 "提示"(prompt)这个词时,是以一种广义的方式来使用的:
"提示"(prompt)是代码生成请求,以及一组可执行的描述(测试),我们可以用它们来验证输出结果。

新流程
我们的新工作流程如下:

  • 编写一个可作为测试执行的提示。
  • 使用提示语要求工具生成通过测试的代码。
  • 将提示作为测试运行 1.
  • 审查通过测试的代码,看它是否以推进设计的方式通过。

在我们原来的工作流程中,有两个审查步骤,而现在我们只有一个--审查风格和设计,而不是正确性。
提示被重新用作测试,简化了我们的工作流程,并消除了流程中的行为不确定性。

这种工作流程在今天绝对是可行的,但也存在一些弊端。我经常需要告诉工具,我希望它在不引入新行为的情况下以最简单的方式通过测试。
目前的工具似乎急于提供比我们要求更多的东西。这只会导致更多的审查和可能的错误。
另一个阻碍因素是疲劳。如果工具在提出建议时经常 "失误",开发就会变得更像调试--比编写代码更累。

在人工智能背景下,"提示 "可以被看作是测试驱动开发,但将 "提示 "作为约束条件的策略可以用于许多其他任务。

举个例子,想象一下让一个工具根据您厨房中的配料和电器清单生成食谱。

  • 您可以用列表提示它,然后收到一份食谱作为输出。
  • 您可以有一个外部检查器,它将您用作提示的清单与生成的食谱一起接收,并验证您是否可以使用清单中的物品进行烹饪。

将这一想法扩展到任何其他类型的装配任务或生成工程任务都非常简单。

生成式人工智能引领我们进入 "生成和检查 "模式
当我们在构思或进行自由形式的创造性工作时,我们可以手动检查输出并使用我们的定性判断。

在工程背景下,我们需要对生成进行限制,并确保其满足我们的要求--"必须具备"。

它们可以指定需要生成的内容,并自动验证其适当性。

这种策略可以帮助我们管理人工智能的 "幻觉 "倾向,并允许我们在需要时引入精确性。