phpunitが遅い
PHPUnitが遅い
カバレッジを出力しているわけでもないのに、phpunitの動作が遅い。
調べたのでメモ。
なぜ遅いか
PHPUnit_TextUI_TestRunner
PHPUnit_TextUI_Command::main() → run() → createRunner() という流れで作られる。
このコンストラクタ
if ($filter === null) { $filter = $this->getCodeCoverageFilter(); } $this->codeCoverageFilter = $filter; $this->loader = $loader; $runtime = new Runtime; $this->canCollectCodeCoverage = $runtime->canCollectCodeCoverage();
getCodeCoverageFilter()
private function getCodeCoverageFilter() { $filter = new PHP_CodeCoverage_Filter; if (defined('__PHPUNIT_PHAR__')) { $filter->addFileToBlacklist(__PHPUNIT_PHAR__); } $blacklist = new PHPUnit_Util_Blacklist; foreach ($blacklist->getBlacklistedDirectories() as $directory) { $filter->addDirectoryToBlacklist($directory); } return $filter; }
カバレッジ対象の Blacklist/Whitelist を準備している。
PHPUnit_Util_Blacklist は、phpunitの依存ライブラリが定義されている。
PHP_CodeCoverage_Filter の addFileToBlacklist(), addDirectoryToBlacklist() は、
最終的にブラックリスト対象のファイルのフルパスをhashに作る。
$black[realpath($path)] = true
のような。
addDirectoryToBlacklist() の方は、ディレクトリを再帰的に渡っていくため、
さらに SplFileInfo::realpath() を使っている。
ディスクの遅い環境だと、この realpath() と SplFileInfo::realpath() が遅くなる。
それが大量に実行されるため、強烈に遅くなる。
カバレッジを出力するのなら仕方ないのだけど、
カバレッジなしのテスト時にまでこれが実行されるのは困った問題。
暫定対応
このような仕様になったのは 4.6.4 からのようなので、4.6.3 を使うことにした。
これだけ違う。
phpunit 4.7.5
[02:35:04 vagrant@phpvm appname]$ php -d auto_prepend_file=xhprof_prepend.php ./vendor/bin/phpunit tests/TestCase/Model/ PHPUnit 4.7.5 by Sebastian Bergmann and contributors. ..................... Time: 1.58 minutes, Memory: 18.50Mb OK (21 tests, 81 assertions)
phpunit 4.6.3
[02:37:09 vagrant@phpvm appname]$ php -d auto_prepend_file=xhprof_prepend.php ./vendor/bin/phpunit tests/TestCase/Model/ PHPUnit 4.6.3 by Sebastian Bergmann and contributors. Configuration read from /projects/prj1/appname/phpunit.xml ..................... Time: 2.64 seconds, Memory: 17.00Mb OK (21 tests, 81 assertions)
Blacklist対象の数にもよるが、今回は45倍早くなった。