使用 PCOV 在 Laravel 中生成代码覆盖率

2024 年 3 月 28 日

Laravel 拥有高效编写功能和单元测试所需的所有测试工具,让您对代码更有信心并减少错误。使用开箱即用的安装,我们可以立即使用 artisan 查看覆盖率报告 --coverage 旗帜:

php artisan test --coverage

如果你没有 PCOV 或者 调试工具 尚未安装,您将收到以下错误:

ERROR  Code coverage driver not available. Did you install Xdebug or PCOV?

根据您的操作系统和 PHP 安装,您可能需要安装 PCOV 或使用 安装文档 。我使用的是 macOS,因此我可以使用 Shivam Mathur 的安装 PCOV 用于 Homebrew 的 homebrew-extensions Tap :

brew install shivammathur/extensions/pcov@8.3

安装 Xdebug 或 PCOV 后,您可以获得覆盖率报告的文本版本:

$ php artisan test --coverage

...

Tests:    26 passed (76 assertions)
Duration: 2.53s

Http/Controllers/Auth/VerifyEmailController ............. 18 / 80.0%
Http/Controllers/Controller ................................. 100.0%
Livewire/Actions/Logout ..................................... 100.0%
Livewire/Forms/LoginForm .................... 53..60, 62..61 / 55.6%
Models/User ................................................. 100.0%
Providers/AppServiceProvider ................................ 100.0%
Providers/VoltServiceProvider ............................... 100.0%
View/Components/AppLayout ................................... 100.0%
View/Components/GuestLayout ................................... 0.0%
                                                       Total: 74.4 %

很不错!

HTML 报告

我们可以获得其他格式的更详细的覆盖率报告,包括我最喜欢的开发格式 HTML 报告:

vendor/bin/pest --coverage-html=build/coverage

使用 --coverage-html flag 将在您的项目中创建一个覆盖率报告,位于 build/coverage 路径,然后您可以打开 index.html 文件以在浏览器中查看它:

Laravel 应用程序中的 HTML 覆盖率
Laravel 中的 HTML 覆盖率

注意:理想情况下,您忽略打算用于覆盖率报告的路径,在我的情况下,我会添加 build.gitignore 。 PHPUnit 有许多可用的覆盖选项。要获得完整列表,您可以运行 phpunit --help

在 phpunit.xml 中配置覆盖范围

我更喜欢使用 CLI 标志来创建覆盖率报告,以便我可以在开发中生成 HTML 报告,并在 CI 构建期间生成 Clover 报告。但是,您可能希望将覆盖率配置为每次运行时都运行 pest 或者 phpunit :

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
>
    <!-- ... -->
    
    <coverage>
        <report>
            <html outputDirectory="build/coverage"/>
            <text outputFile="build/coverage.txt"/>
            <clover outputFile="build/logs/clover.xml"/>
        </report>
    </coverage>
</phpunit>

上面的覆盖配置创建了一个 HTML、文本和 Clover 覆盖工件。现在,每次运行测试套件时,它都会生成覆盖率报告。

我更喜欢使用 CLI 标志来生成覆盖范围的灵活性,但 XML 配置可能比某些配置更可取。您可以了解更多有关 <coverage> PHPUnit 中的标签 XML 配置文件参考

承保范围是如何确定的?

为了生成准确的覆盖率,PHPUnit 需要知道您拥有哪些代码要包含在覆盖率报告中。定义 <include> 推荐使用 element,Laravel 在创建项目时默认会这样做。仅当您想要/拥有应用程序源代码的非标准路径时,才需要更改此设置。

这是什么 <source> 部分应该类似于典型的 Laravel 应用程序安装:

<source>
    <include>
        <directory>app</directory>
    </include>
</source>

如果您使用某种模块模式,则可能需要包含其他目录以反映准确的覆盖范围之外的内容 app 文件夹。此外,PCOV 需要了解这些其他目录,否则您将在其他应用程序文件夹中获得 0% 的覆盖率。

为什么?

因为 PCOV 试图找到 src , lib , 或者 app 什么时候 pcov.directory 未设置。我们可以通过创建一个示例文件来演示这一点,以便您可以直观地了解如何进行设置。

非标准代码路径的覆盖范围

我建议坚持 Laravel 的约定,但是您可能会遇到这样的情况:您处理的现有代码在除 app 文件夹。我们可以配置 PHPUnit 和 PCOV 来将此代码包含在覆盖率报告中,并进行一些调整。

让我们模仿这个;假设您从一个新的 Laravel 应用程序开始,创建一个示例模块:

# inside a Laravel app
mkdir -p module/Example/src

添加以下内容到 Example.php 在里面 src 示例模块的文件夹:

<?php

namespace Module\Example;

class Example
{
    public function sayHello($name = 'World')
    {
        return "Hello, {$name}!";
    }
}

接下来,我们需要自动加载此代码以运行涵盖此示例类的测试。打开 composer.json 并添加以下自动加载行:

"autoload": {
    "psr-4": {
        "App\\": "app/",
        "Module\\Example\\": "module/Example/src/",
        "Database\\Factories\\": "database/factories/",
        "Database\\Seeders\\": "database/seeders/"
    }
}

更新composer.json文件后,运行 composer dumpautoload 更新自动加载器并找到新路径。

正如我之前提到的,PHPUnit 需要了解源代码的位置。打开 phpunit.xml 并更新 <source> 配置以包含我们的模块:

<source>
    <include>
        <directory>app</directory>
        <directory>module/*/src</directory>
    </include>
</source>

接下来,创建一个测试文件,以便我们可以说明模块的 0% 覆盖率报告:

php artisan make:test --unit ExampleModuleTest

将以下内容添加到创建的 ExampleModuleTest.php 文件:

use Module\Example\Example;

test('it says hello', function () {
    $subject = new Example();
    expect($subject->sayHello())->toEqual('Hello, World!');
});

如果您现在运行测试套件,您将获得 0% 的覆盖率报告 module 文件夹:

vendor/bin/pest --coverage-html=build/coverage

如果您打开最新的覆盖率报告,您会注意到丢失的覆盖率,即使测试已通过:

缺少模块覆盖
缺少模块覆盖

我们可以通过更改一些 PCOV 配置选项来解决此问题:

php -d pcov.enabled=1 -d pcov.directory=. -dpcov.exclude="~vendor~" \
  vendor/bin/pest --coverage-html=build/coverage

在典型的 Laravel 应用程序结构中,我们不必这样做,因为覆盖率报告将查找 app 自动文件夹。但是,如果您的项目需要报告其他路径的覆盖率,我们必须设置 pcov.directory 到项目的根目录。自从 vendor 文件夹位于项目的根目录中,我们不想扫描 vendor ,我们可以给 PCOV pcov.exclude 图案。

如果您运行上述命令,然后刷新 HTML 报告,您应该会看到报告的覆盖率!

Laravel 应用程序中的模块覆盖率
Laravel 应用程序中的工作模块覆盖率

包含这些 PCOV 选项很乏味,所以我更喜欢添加一些编写器脚本来为我完成此操作:

"scripts": {
  "test:html": [
    "Composer\\Config::disableProcessTimeout",
    "php -d pcov.enabled=1 -d pcov.directory=. -dpcov.exclude=\"~vendor~\" vendor/bin/pest --coverage-html=build/coverage"
  ]
}

您现在可以运行 composer test:html 生成 HTML 覆盖率报告。我也喜欢定义一个 test:ci 脚本,我可以使用它进行持续集成(clover)并将覆盖工件上传到类似的服务 声纳

您现在拥有为 Laravel 应用程序生成覆盖率报告所需的所有工具,并在项目需要时考虑非标准路径的覆盖率!


帖子 使用 PCOV 在 Laravel 中生成代码覆盖率 首先出现在 Laravel 新闻

加入 Laravel 时事通讯 直接在您的收件箱中获取所有此类最新的 Laravel 文章。