Laravel 测试增加内存使用

mrh*_*rhn 5 php phpunit laravel

Time: 1.89 minutes, Memory: 526.00MB

OK (487 tests, 2324 assertions)
Run Code Online (Sandbox Code Playgroud)

这是我测试 Laravel API 的 phpunittest 结果,内存消耗一直在增加,感觉就像我尝试了互联网上的所有帖子和答案,以了解在测试时不断增加内存的原因。从自己的调试中,应用程序被丢弃了它应该进行的每一个测试。

一切都非常标准,createApplication 方法看起来像这样。

public function createApplication()
{
    // Ran out of memory
    ini_set('memory_limit', '1024M');

    $app = require __DIR__ . '/../bootstrap/app.php';

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

    return $app;
}
Run Code Online (Sandbox Code Playgroud)

得出的结论是内存泄漏在,没有得到正确清理。

$app = require __DIR__ . '/../bootstrap/app.php';

$app->make(Kernel::class)->bootstrap();
Run Code Online (Sandbox Code Playgroud)

Fin*_*sse 5

这是我找到的最简单、最可靠的解决方案。它没有我之前的回答中描述的缺点。

将文件中的<phpunit>标签processIsolation属性值更改为。正确文件开头的示例:truephpunit.xmlphpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="true"
         stopOnFailure="false">
...
Run Code Online (Sandbox Code Playgroud)

它是如何工作的:它使 PhpUnit 为每个测试启动一个新的 PHP 进程。在单独的进程中运行测试会强制 PHP 在测试结束后释放所有内存。它会减慢测试速度,但这是低内存消耗和可靠性的代价。

或者,如果您需要在单独的进程中仅运行某些测试,则可以向测试类的文档块添加@runTestsInSeparateProcesses注释:

/**
 * @runTestsInSeparateProcesses
 */
class HeavyTest extends TestCase
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)


Fin*_*sse 1

这是一个简单的解决方案。我在 Laravel 5.5 中测试了它。将其设置为文件的内容tests/CreatesApplication.php

namespace Tests;

use Illuminate\Contracts\Console\Kernel;

trait CreatesApplication
{
    /**
     * @var \Illuminate\Foundation\Application
     */
    protected static $application;

    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        if (!isset(static::$application)) {
            static::$application = require __DIR__ . '/../bootstrap/app.php';
            static::$application->make(Kernel::class)->bootstrap();
        }

        return static::$application;
    }

    /**
     * {@inheritDoc}
     */
    protected function tearDown()
    {
        // Required if you use HTTP tests
        $this->app['auth']->guard(null)->logout();
        $this->app['auth']->shouldUse(null);
        $this->flushSession();

        // Always required
        $this->app = null;
        parent::tearDown();
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码使测试对所有测试使用相同的 Laravel 应用程序实例,而不是为每个测试创建一个新实例。这也会导致更快的测试运行。

该解决方案有缺点:

  • 如果某个测试修改了应用程序,其他测试可能会失败,因为它们期望应用程序未更改。
  • 如果测试使用DatabaseTransactionsDatabaseMigrations特征,则当 PHPUnit 测试运行的所有测试完成后,数据库将被重置。