在软件开发过程中,编写清晰、高效的单元测试至关重要,这些测试应当实际有效。

有效的单元测试不仅能捕捉错误,还能帮助你确信代码可维护且可靠。但手动创建全面的单元测试套件需要时间和资源。

近年来,人工智能领域的一些最新发展有望帮助自动化单元测试开发过程。今年2月,Meta的研究人员发表了一篇论文,题为使用大型语言模型自动化单元测试改进,介绍了一种自动化单元测试的创新方法。

他们的研究聚焦于一个名为TestGen-LLM的新工具,该工具探索使用LLM分析现有的单元测试并加以改进,以提高代码覆盖率。

尽管TestGen-LLM的代码并未发布,但本文将介绍一个受其研究启发而成的开源替代方案。你将了解到它是如何生成测试套件的,为什么它优于大多数LLM,以及如何获取这项技术并开始尝试使用。

目录

Meta的TestGen-LLM

Meta的TestGen-LLM通过利用大型语言模型(LLM)的力量,解决了单元测试编写这一耗时任务。通用LLM,如Gemini或ChatGPT,可能会在单元测试代码的特定领域、测试语法以及生成无价值测试方面遇到困难。但TestGen-LLM专门为单元测试而设计。

这种专业化使它能够理解代码结构和测试逻辑的复杂性,从而导致更针对性的测试套件,并生成实际上增加代码覆盖率的测试。

TestGen-LLM能够评估单元测试并识别改进区域。它通过理解常见的测试模式来实现这一点,这些模式是它经过训练的。但仅生成测试对于适当的代码覆盖是不够的。

Meta的研究人员在TestGen-LLM中实现了安全措施,以确保它编写的测试的有效性。这些安全措施被称为过滤器,它们充当质量控制机制。它们消除了建议:

  • 无法编译

  • 始终失败,或者

  • 实际上没有提高代码覆盖率(其他测试已经覆盖的建议)。

TestGen-LLM是如何工作的?

TestGen-LLM采用了一种名为“保证基于LLM的软件工程”(Assured LLMSE)的方法。TestGen-LLM只是向现有的测试类中添加了额外的测试用例,保留了所有现有的测试用例,从而确保不会有回归。

测试生成工作流程(来自TestGen_LLM论文

TestGen-LLM生成了一批测试用例,然后过滤掉那些不能运行的测试用例,并丢弃那些不通过的测试用例。最后,它丢弃那些不增加代码覆盖率的测试用例。

在使用TestGen-LLM自动化测试套件后,Meta使用一名人类评审员接受或拒绝生成的测试用例,在最佳报告案例中,生成的测试用例的接受率为73%。

根据论文,TestGen-LLM在每次运行时生成一个测试用例,然后添加到之前由开发者编写的现有测试套件中。但它不一定为任何给定的测试套件生成测试用例。

TestGen-LLM的有效性在Meta内部测试马拉松活动中得到了证明。在这里,该工具用于分析现有的测试套件并提出改进建议。结果很有希望:

“TestGen-LLM的75%测试用例构建正确,57%可靠地通过,25%增加了覆盖率。在Meta的Instagram和Facebook测试马拉松活动中,它改进了应用到其中的所有类的11.5%,其中73%的建议被Meta软件工程师接受用于生产部署。”

同样,TestGen-LLM的推荐在参与测试狂欢节的开发者看来是有用且相关的。

开源实现(Cover-Agent)

Meta的TestGen-LLM研究具有很大的潜力改变单元测试和自动化测试生成的现状。该工具很可能会利用专门在代码上训练的LLM来提高代码覆盖率和加快测试创建的速度。但由于TestGen-LLM的代码并未发布,这项技术并不是任何人都可以使用的。

对这项技术感兴趣的开发商可能会对缺乏公开可用的代码感到沮丧。毕竟,Meta的TestGen-LLM研究为我们展示了一个自动化测试未来的诱人前景。

能够深入了解最新技术的内部工作原理,理解其决策过程,甚至可能参与塑造其发展,这非常吸引人。尽管缺乏Meta的代码是一个障碍,但有一个名为Cover-Agent的开源实现可以作为有用的替代。

CodiumAI的Cover-Agent是第一个基于TestGen-LLM的开源自动化测试工具实现。受到Meta研究的启发,Cover-Agent现在成为了开源AI驱动的单元测试发展前沿的一部分。

为什么需要专门的测试聚焦LLM?

既然大多数LLM(如ChatGPT和Gemini)都能够生成测试,那么为什么还要研究新技术呢?

覆盖代理和测试生成-大型语言模型旨在成为高效单元测试的下一步。它们的目的是避免开发者在使用大型语言模型生成测试时遇到的常见陷阱,例如:

  • 大型语言模型幻觉

  • 生成不增加价值的测试

  • 生成忽略某些代码部分的测试,导致代码覆盖率低

为了克服这些挑战(特别是对于回归单元测试),测试生成-大型语言模型的研究人员提出了以下标准,生成测试必须满足这些标准才能被接受:

  • 生成的测试是否可以正常编译和运行?

  • 测试是否增加了代码覆盖率?

  • 它是否有价值?

  • 它是否符合我们可能有的任何其他要求?

这些是生成测试必须解决的基本问题和要求,才能被认为是现有技术的升级。覆盖代理提供了回答这些问题和要求的测试,其程度令人惊叹。

覆盖代理是如何工作的?

Cover-Agent 是一套更广泛的工具的一部分,旨在自动化创建软件项目的单元测试。利用 TestGen-LLM 生成式 AI 模型,它旨在简化和加速测试过程,确保高质量的软件开发。

系统由几个组件组成:

  • 测试运行器:执行命令或脚本来运行测试套件并生成代码覆盖率报告。

  • 覆盖率解析器:验证随着测试的添加代码覆盖率是否增加,确保新测试对整体测试效果有所贡献。

  • 提示构建器:从代码库中收集必要的数据并构建传递给大语言模型(LLM)的提示。

  • AI 调用器:与 LLM 互动,根据提供的提示生成测试。

这些组件与 TestGen-LLM 一起工作,仅生成保证改进现有代码库的测试。

如何使用Cover-Agent

要求

在开始使用Cover-Agent之前,您需要满足以下要求:

  • OPENAI_API_KEY 已设置在您的环境变量中,这是调用 OpenAI API 所必需的。

  • 代码覆盖工具:需要一个Cobertura XML代码覆盖报告,以便工具正确运行。例如,在Python中,您可以使用 pytest-cov。在运行Pytest时,添加 --cov-report=xml 选项。

安装

如果您直接从仓库运行Cover-Agent,您还需要:

  • 在您的系统上安装Python。

  • 安装Poetry以管理Python包依赖关系。您可以在 这里 找到Poetry的安装说明。

独立运行时

您可以将Cover-Agent作为Python Pip包安装,或者作为独立的可执行文件运行。

Python Pip

通过GitHub直接安装Python Pip包,请运行以下命令:

pip install git+https://github.com/Codium-ai/cover-agent.git

二进制

在没有安装Python环境的系统上运行二进制文件(例如,在不含Python的Docker容器内)。您可以前往项目的发布页面下载适合您系统的版本。

仓库设置

运行以下命令以安装所有依赖项并从源代码运行项目:

poetry install

运行代码

在安装Pip包或下载可执行文件后,您现在可以运行Cover-Agent来生成和验证单元测试。

从命令行执行,使用以下命令:

cover-agent \
--source-file-path "path_to_source_file" \
--test-file-path "path_to_test_file" \
--code-coverage-report-path "path_to_coverage_report.xml" \
--test-command "test_command_to_run" \
--test-command-dir "directory_to_run_test_command/" \
--coverage-type "type_of_coverage_report" \
--desired-coverage "desired_coverage_between_0_and_100" \
--max-iterations "max_number_of_llm_iterations" \
 --included-files "<optional_list_of_files_to_include>"

您可以使用本仓库中的示例项目来运行此代码作为测试。

命令行参数

  • source-file-path: 包含我们要测试的函数或代码块的文件的路径。

  • test-file-path: 代理将在此文件中编写测试的路径。最好创建一个包含至少一个测试和必需的导入语句的此文件的骨架。

  • 代码覆盖报告路径: 保存代码覆盖报告的路径。

  • 测试命令: 运行测试的命令(例如 pytest)。

  • 测试命令目录: 测试命令应运行的目录。将此设置为根目录或主文件的位置,以避免相对导入的问题。

  • 覆盖类型: 要使用的覆盖类型。Cobertura 是一个很好的默认选项。

  • 期望的覆盖率: 覆盖目标。越高越好,尽管 100% 通常是不切实际的。

  • 最大迭代次数: 代理应尝试生成测试代码的次数。更多迭代可能会导致 OpenAI 令牌使用量增加。

  • 附加说明:确保代码以特定方式编写的提示。例如,在这里我们指定代码应格式化为适用于测试类中。

运行命令后,代理开始编写并迭代测试。

如何使用Cover-Agent

是时候测试一下Cover-Agent了。我们将使用一个简单的calculator.py应用来比较手动和自动化测试的代码覆盖率。

手动测试

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

def multiply(a, b):
    return a * b

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

这是位于测试文件夹中的test_calculator.py。

# tests/test_calculator.py
from calculator import add, subtract, multiply, divide

class TestCalculator:

    def test_add(self):
        assert add(2, 3) == 5

为了查看测试覆盖率,我们需要安装pytest-cov,这是一个用于覆盖报告的pytest扩展,前面已经提到过。

pip install pytest-cov

使用以下命令运行覆盖分析:

pytest --cov=calculator

输出显示:

Name            Stmts   Miss  Cover
-----------------------------------
calculator.py      10      5    50%
-----------------------------------
TOTAL              10      5    50%

上述输出显示,calculator.py中的10条语句中有5条未执行,导致代码覆盖率仅为50%。对于更大的代码库,这将成为一个严重问题,导致进度受阻。

现在让我们看看Cover-Agent是否能做得更好。

使用Cover-Agent的自动化测试

要设置Codium的Cover-Agent,请按照以下步骤操作:

首先,安装 Cover-Agent:

pip install git+https://github.com/Codium-ai/cover-agent.git

确保您已经在环境变量中设置了 OPENAI_API_KEY,因为这是访问 OpenAI API 所必需的。

接下来,编写在终端中开始生成测试的命令:

cover-agent \
--source-file-path "calculator.py" \
--test-file-path "tests/test_calculator.py" \
--code-coverage-report-path "coverage.xml" \
--test-command "pytest --cov=. --cov-report=xml --cov-report=term" \
--test-command-dir "./" \
--coverage-type "cobertura" \
--desired-coverage 80 \
--max-iterations 3 \
--openai-model "gpt-4o" \
--additional-instructions "Since I am using a test class, each line of code (including the first line) needs to be prepended with 4 whitespaces. This is extremely important to ensure that every line returned contains that 4 whitespace indent; otherwise, my code will not run."

这生成了以下代码:

import pytest
from calculator import add, subtract, multiply, divide

class TestCalculator:

    def test_add(self):
        assert(add(2, 3), 5

    def test_subtract(self):
        """
        Test subtracting two numbers.
        """
        assert subtract(5, 3) == 2
        assert subtract(3, 5) == -2

    def test_multiply(self):
        """
        Test multiplying two numbers.
        """
        assert multiply(2, 3) == 6
        assert multiply(-2, 3) == -6
        assert multiply(2, -3) == -6
        assert multiply(-2, -3) == 6

    def test_divide(self):
        """
        Test dividing two numbers.
        """
        assert divide(6, 3) == 2
        assert divide(-6, 3) == -2
        assert divide(6, -3) == -2
        assert divide(-6, -3) == 2

    def test_divide_by_zero(self):
        """
        Test dividing by zero, should raise ValueError.
        """
        with pytest.raises(ValueError, match="Cannot divide by zero"):
            divide(5, 0)

您可以看到,代理还编写了检查任何边缘情况错误的测试。

现在,再次测试覆盖率:

pytest --cov=calculator

输出:

Name            Stmts   Miss  Cover
-----------------------------------
calculator.py      10      0   100%
-----------------------------------
TOTAL              10      0   100%

在这个例子中,我们达到了100%的代码覆盖率。对于更大的代码库,这个过程相对相同。您可以阅读这份指南,了解如何对更大的代码库进行逐步操作。

虽然 Cover-Agent 代表了测试技术的一大进步,但值得注意的是,这项技术仍处于早期阶段。持续的研究和开发对于进一步改进和更广泛的应用至关重要,codiumAI 邀请您为这个开源工具做出贡献。

Open Source Cover-Agent 的优势

Cover-Agent 的开源性质带来了几个优势,应该有助于推动这项技术前进。其中包括:

  • 易用性:开源性质使得基于 LLM 的测试实验变得易于访问,并且适合不同背景的开发者这将增加用户数量,导致更好的技术开发和更多应用的产生。

  • 合作:开发人员可以做出贡献、提出改进建议、提出新功能以及报告问题。Cover-Agent将会迅速发展成为一个适合开发人员的完美项目。

  • 透明度:关于内部运作的信息是公开的,这促进了信任,并最终增加技术的潜力。

除了开源的优势之外,Cover-Agent还为开发者提供了自己的一系列强大优势:

  • 简单访问:开发者可以轻松安装并尝试基于LLM的测试。这使得可以亲身体验这项技术的 capabilities,而不会干扰他们的工作流程。

  • 定制以满足特定需求:Cover-Agent的开源特性让开发者能够根据他们的特定项目需求调整工具。这可能包括修改所使用的LLM模型,调整训练数据以更好地反映他们的代码库,或将与Cover-Agent集成的现有测试框架。这种程度的定制让开发者能够以符合他们项目需求的方式,充分利用基于LLM的测试的强大功能。

  • 易于集成:它能够轻松与VSCode(一款流行的代码编辑器)集成,使得与现有工作流程的集成变得轻而易举。您还可以轻松地将其与现有的人工编写的测试集成。

您如何为Cover-Agent做出贡献?

Cover-Agent 源代码可通过 这个 GitHub 仓库 公开获取。他们鼓励来自各种背景的开发者测试他们的产品,并为这项新技术的进一步改进和增长做出贡献。

结论

基于 LLM 的测试改进工具对革命化开发者进行单元测试的方法具有巨大潜力。通过利用专门针对代码训练的大型语言模型的力量,这些工具可以简化测试创建,提高代码覆盖率,并最终提高软件质量。

尽管 Meta 的 TestGen-LLM 研究提供了宝贵的洞察,但公开可用的代码的缺失阻碍了更广泛的应用和持续发展。幸运的是,Cover-Agent 提供了一个易于访问和自定义的解决方案。它使开发者能够尝试基于 LLM 的测试并为其进化做出贡献。

TestGen-LLM 和 Cover-Agent 的潜力巨大,通过开发者的贡献进一步开发将导致一个革命性的工具,将永远改变自动测试生成。

如果你觉得这有帮助,请在领英推特上与我联系。