PHPUnit 加速技巧分享

file

具有高效的测试一如编写高效的应用同样重要。做为开发者来讲,迅速得知你刚编写的代码是否可以正常运行,可以让开发效率大大提高。接下来咱们将会介绍一些能够快速实现的小技巧,让你的代码测试变得更快。php

该示例测试套件有意地模拟更普遍的测试集合,并突出改进的可行性。真实状况下,效率的提高可能有所差别。html

ParaTest

这个包 是一个用来运行你的测试套件的 PHPUnit 扩展。 和 PHPUnit 不同的是它能够利用你的多核 CPU 来并行的运行测试用例。laravel

你能够经过 composer 来将它做为一个开发依赖安装之后开始使用 ParaTestgit

composer require --dev brianium/paratest

复制代码

如今咱们就能够像调用 PHPUnit 同样来调用 ParaTest 了。它会自动的根据你机器 CPU 核心数来判断要启动多少个进程。github

上面,你能够看到在控制台中输出了运行测试用例启动了5个并行的进程。对比一下,下面用 PHPUnit 运行了一样的测试用例。算法

1.49 秒 和 6.15秒 !sql

尽管 ParaTest 能够本身肯定进程数,你也能够尝试设置进程数针对你的机器进行优化。使用  ---processes 选项,你能够增长或减小进程数,由于并非进程数越多测试效果越好。数据库

./vendor/bin/paratest --processes 6

复制代码

警告: 使用 ParaTest 测试数据库前,须要考虑如何准备数据。若是使用 Lavarel 的  RefreshDatabase ,运行测试用例后会回滚或者迁移数据库来写入 。 相反的是,经过  DatabaseTransactions  跳过数据持久化, 这在运行测试期间不会尝试修改数据。bootstrap

重试失败的测试

PHPUnit 有个很是方便的功能就是,容许你从新只运行上次测试中失败的测试.。若是你正在进行红绿复建风格的 TDD 开发,它将会加快你的开发周期。让咱们从一个经过全部现存测试的测试套件来了解一下它这个功能。缓存

接下来,新增一个 red-green-refactor 测试模型的测试用例,预期失败:

在更改代码库以后你认为新测试会经过,你想从新运行该测试套件以期能按预期运行。问题在于这个套件如今已经要花 1.3 秒的时间才能运行,随着测试代码量的增长,所需严重等待的时间也随之增长。

若是咱们只能运行失败的测试,那不是很好? 很是幸运的是 PHPUnit v7.3添加了这样作的能力

为了实现这个功能,请将 cacheResult =“true” 添加到 phpunit.xml配置中。 PHPUnit 会始终记住之前哪些测试失败了。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit cacheResult="true"
         backupGlobals="false"
         ...>

复制代码

如今,当咱们运行咱们的测试单元时, PHPUnit 将记住哪些测试失败并使用如下选项让咱们能够从新运行那些失败的测试单元。

./vendor/bin/phpunit --order-by=defects --stop-on-defect

复制代码

咱们再也不须要等待整个测试单元运行,以查看咱们试图解决的一个测试是否正在经过。

将缓存文件 .phpunit.result.cache 添加到 .gitignore 也是一个好主意,这样它就不会最终被提交到你的仓库里。

慢测试分组

PHPUnit 容许你用 @group 注解来将测试用例添加到不一样的「分组」。若是你有一些测试用例尤为的慢的话,最好是将他们分到同一个组。

class MyTest extends TestCase
{
    public function test_that_is_fast()
    {
        $this->assertTrue(true);
    }

    /**
     * @group slow
     */
    public function test_that_is_slow()
    {
        sleep(10);

        $this->assertTrue(true);
    }

    /**
     * @group slow
     */
    public function test_that_is_slow_2_adrians_revenge()
    {
        sleep(10);

        $this->assertFalse(false);
    }
}

复制代码

在这个例子中,咱们有两个测试用例要运行10秒钟。 在咱们开发周期内最后一件要作的事情就是运行测试用例,尤为是在作测试驱动开发的时候须要测试用例瞬时执行完成。

因为两个慢的测试用例都在同一个分组因此你能够经过 PHPUnit 的 --exclude-group 选项在某一次测试运行中来排除他们。

./vendor/bin/phpunit --exclude-group slow

复制代码

这个命令将会运行你测试用例中除了 slow 分组的全部测试用例。 测试用例分组还有一个好处,好比说你须要将你全部的慢测试用例整理成文档以便后面再来优化他们。

然而在部署到生产环境前进行一些检查确保全部测试用例能经过,包括慢的测试用例。 设置一个 CI 管道来运行测试用例会是个不错的方法。

过滤测试

PHPUnit 有一个 --filter 选项,它接受一个模式来肯定运行哪些测试。例如,若是您将全部测试配置命名空间 ,则能够经过指定命名空间来运行特定的测试子集。 如下命令仅在 Tests\Unit\Models 命名空间中运行测试并排除全部其余命令。

./vendor/bin/phpunit --filter 'Tests\\Unit\\Models'

复制代码

--filter 选项是灵活的,容许经过 methodNameClass::methodName 进行过滤,甚至能够经过带有 /path/to/my/test.php 的文件路径进行过滤。您应该查看此选项的 PHPUnit docs 并查看更多的内容。

密码哈希次数

Laravel 默认使用 bcrypt 密码哈希算法,这种设计在系统资源上缓慢且昂贵。若是您的测试是验证用户密码,能够经过设置算法使用的次数来减小测试运行的时间,由于它执行的次数越多,所需的时间就越长。

若是你的应用程序与 laravel/laravelproject 中的最新更改保持同步,你会发现哈希次数的数量可使用环境变量进行自定义。bcrypt 容许的最小次数已经设置为4,在 phpunit.xml file.

可是,若是您没有同步最新的更新,可使用 Hash 门面在CreatesApplication trait 中设置它。

public function createApplication()
{
    $app = require __DIR__.'/../bootstrap/app.php';

    $app->make(Kernel::class)->bootstrap();

    // 设置 bcrypt 哈希次数...
    Hash::rounds(4);

    return $app;
}

复制代码

内存数据库

利用内存数据库 SQLite ,是另外一种加速测试的方式。 你能够经过在 phpunit.xml  配置文件里添加两个环境字段,来迅速开启它。

<php>
    ...
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE" value=":memory:"/>
</php>

复制代码

说明:尽管这样看上去很容易,你应该考虑生产环境数据库一致性问题。若是你在生产环境使用了 MySQL 数据库,你应该警戒引入不一样数据库所带来的测试上的不一样,好比 SQLite。我在这篇文章 my feature test suite setup 里描述了不少细节上的不一样点。我认为相比经过提高一点速度带来的好处,保持生产环境一致更重要。

禁用 Xdebug

若是你平时用不到 Xdebug 的话,能够禁用掉它,由于它会下降 PHP 执行速度,致使测试用例运行缓慢。若是你平常使用它来调试的话,为了执行测试而禁用它可能不是一个好的选择 —— 但你始终要知道这一点当你关注测试用例执行速度时。

你能够在下面这个测试用例看到,一旦咱们禁用了 Xdebug,执行速度将会有极大的提升。下面是这个测试用例在 Xdebug 启用时的执行状况:

以及一样的测试用例在 Xdebug 禁用时的执行状况:

修复测试速度过慢

固然咱们最但愿看到的段落是是:修复测试速度过慢!若是您正在努力肯定哪些测试致使测试单元变慢时,您可能须要查看 PHPUnit Report 。它是一个开源工具,容许您经过生成以下所示的云可视化您的测试单元的性能,其中较大的气泡表明慢速测试。这将使您可以在单元中找到最慢的测试并逐步提升其性能。

file

转自 PHP / Laravel 开发者社区 laravel-china.org/topics/2234…

相关文章
相关标签/搜索