LoginSignup
52
43

More than 5 years have passed since last update.

PHPUnitのコードカバレッジが遅いからってあきらめずに、並列実行ためしてみる

Last updated at Posted at 2016-08-09

はじめに

PHPUnitにはコードカバレッジ解析の機能があります。
このカバレッジの出力には、かなり時間がかかります。
チームメンバーからCIのテストが遅いので何とかしてほしいと、issuesがあがってきたので、スピード改善できないか検討し、最終的には並列実行することで、大幅に改善することができましたので、紹介します。

コードカバレッジの出力

カバレッジを出力するには、phpunitコマンド実行時のオプションに--coverage-*を指定します。
phpunitのヘルプに詳しい説明があります。

$ bin/phpunit --help
PHPUnit 4.8.6 by Sebastian Bergmann and contributors.

Usage: phpunit [options] UnitTest [UnitTest.php]
       phpunit [options] <directory>

Code Coverage Options:

  --coverage-clover <file>  Generate code coverage report in Clover XML format.
  --coverage-crap4j <file>  Generate code coverage report in Crap4J XML format.
  --coverage-html <dir>     Generate code coverage report in HTML format.
  --coverage-php <file>     Export PHP_CodeCoverage object to file.
  --coverage-text=<file>    Generate code coverage report in text format.
                            Default: Standard output.
  --coverage-xml <dir>      Generate code coverage report in PHPUnit XML format.

phpunitを分割して実行し、最後にカバレッジファイルをマージする

phpunitを並列で実行させるためには、複数に分割して実行する必要があります。
サブディレクトリなど、何らかの単位で分割して実行するようにし、最後に出力されたそれぞれのカバレッジファイルをマージします。

phpcovのインストール

カバレッジファイルのマージには、phpcovが必要になりますので、composerからインストールします。

$ composer require --dev 'phpunit/phpcov'

分割して実行

下記のようにディレクトリ別にテストを実行し、最後にカバレッジファイルをマージします。

bin/phpunit --coverage-php var/report/coverage_foo.cov tests/Foo
bin/phpunit --coverage-php var/report/coverage_bar.cov tests/Bar
bin/phpunit --coverage-php var/report/coverage_baz.cov tests/Baz
bin/phpcov merge --clover var/report/coverage.xml var/report/

並列でテストを実行

phpcovのREADMEに、GNU parallelで並列実行するサンプルが記載されているので、試してみます。

GNU parallelのインストール

事前準備として、GNU parallelをパッケージ経由もしくはソースをビルドしてインストールします。

  • パッケージからインストール
  $ apt-get install parallel
  • ソースからインストール
  $ wget http://ftp.gnu.org/gnu/parallel/parallel-20160722.tar.bz2
  $ tar -jxvf parallel-20160722.tar.bz2
  $ cd parallel-20160722
  $ ./configure
  $ make && sudo make install

並列で実行

READMEに従い、並列で実行するスクリプトを準備します。

parallel --gnu --halt-on-error=now,fail=1 ::: \
  bin/phpunit --coverage-php var/report/coverage_foo.cov tests/Foo \
  bin/phpunit --coverage-php var/report/coverage_bar.cov tests/Bar \
  bin/phpunit --coverage-php var/report/coverage_baz.cov tests/Baz
bin/phpcov merge --clover var/report/coverage.xml var/report/

READMEには、--halt-on-error=now,fail=1のオプションは記述ありませんが、エラーが起きたときは即時にfailしてほしかったので、追加しました。
詳しくは公式のマニュアルを参照ください。

ローカルの仮想環境で確認するときの注意事項

あとは、準備したスクリプトを実行するだけなのですが、ローカルの仮想環境で実行するときには、CPU数をデフォルトの1から2以上に変更しないと、並列実行の効果がほとんど得られません。

Docker for Macの場合(2018-09-20更新)

Dockerの場合は、PreferencesからCPU数を変更できます。

参考URL

Vagrantの場合

Vagrantの場合は、Vagrantfileに下記の記述を追加します。

# Vagrantfile
  config.vm.provider :virtualbox do |vb|
    vb.customize ['modifyvm', :id, '--cpus', '2', '--ioapic', 'on']
  end

参考URL

結果

どのくらい早くなるかは、一概には言えませんが、例えば下記のように実行時間がかかっているとすれば、7分かかっていた処理が、tests/Baz => 3分 + phpcov merge => 1分 で4分にはなるイメージです。

  • tests/Foo => 1分
  • tests/Bar => 2分
  • tests/Baz => 3分
  • phpcov merge => 1分

上記以外のソリューション

いずれも今回は検討のみで試したわけではないのですが、上記以外にもいくつかソリューションがあります。

特定のブランチのみカバレッジを測る

polidogさんのブログ記事『CircleCIでmasterブランチのみカバレッジを測るようにphpunitを実行する』に詳しい説明があります。

CIの並列実行機能を使う

CIによっては、CI側で並列実行の機能を提供しています。

おわりに

テストの実行時間は開発効率に直接影響します。
今回紹介した方法は、特定のCIに依存したものではないので、参考にしてみてください。

52
43
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
43