Prev Next

第14章 コードカバレッジ解析

ユニットテストでコードをテストする方法はわかりました。でも、 テストそのものをテストするにはどうしたらいいのでしょう? テストされていないコードを見つけるには? 言い換えれば、まだテストで カバーされていない部分を見つけるには? 完全にテストができたことをどうやって確認するの? これらのすべての疑問に対する答えとなるのが、コードカバレッジ解析という手法です。 コードカバレッジ解析を行うと、 コードのどの部分がテストされたのかを調べることができるようになります。

PHPUnit のコードカバレッジ解析では、Xdebug 拡張モジュールが提供するステートメントカバレッジ機能を利用しています。 ステートメントカバレッジというのは、たとえば 100 行のコードで構成されるメソッドがあった場合に、 もしテストで実際に実行されたのがそのうちの 75 行だけだったなら、 そのメソッドのコードカバレッジは 75 パーセントだと考えるということです。

それでは、例 13.3BankAccount クラスについての コードカバレッジレポートを作成してみましょう。

phpunit --coverage-html ./report BankAccountTest
PHPUnit 3.2.10 by Sebastian Bergmann.

...

Time: 0 seconds

OK (3 tests)

Generating report, this may take a moment.

図 14.1 は、コードカバレッジレポートの一部を抜粋したものです。 テスト時に実行された行は、緑色で強調表示されます。 実行可能なコードであるにもかかわらず実行されなかった行については赤色で強調表示されます。 また、"無意味なコード" についてはオレンジ色で強調表示されます。 行の左にある数字は、その行をカバーするテストの数を表します。

図14.1 setBalance() のコードカバレッジ

setBalance() のコードカバレッジ

BankAccount のコードカバレッジレポートからわかることは、 setBalance()depositMoney() をコールするテストがまだ存在しないということ、 そして withdrawMoney() に正しい値を指定した場合のテストも存在しないということです。 BankAccountTest クラスに追加するテストを 例 14.1 に示します。これによって、BankAccount クラスのテストケースを完全に網羅できるようになります。

例 14.1: 完全なコードカバレッジを達成するために欠けているテスト

<?php
require_once 'PHPUnit/Framework.php';
require_once 'BankAccount.php';

class BankAccountTest extends PHPUnit_Framework_TestCase
{
// ...

public function testDepositWithdrawMoney()
{
$this->assertEquals(0, $this->ba->getBalance());
$this->ba->depositMoney(1);
$this->assertEquals(1, $this->ba->getBalance());
$this->ba->withdrawMoney(1);
$this->assertEquals(0, $this->ba->getBalance());
}
}
?>

図 14.2 は、 テストを追加した後の setBalance() のコードカバレッジです。

図14.2 setBalance() にテストを追加した後のコードカバレッジ

setBalance() にテストを追加した後のコードカバレッジ

カバーするメソッドの指定

テストコードで @covers アノテーションを使用すると、 そのテストメソッドがどのメソッドをテストしたいのかを指定することができます。 これを指定すると、指定したメソッドのコードカバレッジ情報のみを考慮します。 例 14.2 に例を示します。

例 14.2: どのメソッドを対象とするかを指定したテスト

<?php
require_once 'PHPUnit/Framework.php';
require_once 'BankAccount.php';

class BankAccountTest extends PHPUnit_Framework_TestCase
{
protected $ba;

protected function setUp()
{
$this->ba = new BankAccount;
}

/**
* @covers BankAccount::getBalance
*/
public function testBalanceIsInitiallyZero()
{
$this->assertEquals(0, $this->ba->getBalance());
}

/**
* @covers BankAccount::withdrawMoney
*/
public function testBalanceCannotBecomeNegative()
{
try {
$this->ba->withdrawMoney(1);
}

catch (BankAccountException $e) {
$this->assertEquals(0, $this->ba->getBalance());

return;
}

$this->fail();
}

/**
* @covers BankAccount::depositMoney
*/
public function testBalanceCannotBecomeNegative2()
{
try {
$this->ba->depositMoney(-1);
}

catch (BankAccountException $e) {
$this->assertEquals(0, $this->ba->getBalance());

return;
}

$this->fail();
}

/**
* @covers BankAccount::getBalance
* @covers BankAccount::depositMoney
* @covers BankAccount::withdrawMoney
*/

public function testDepositWithdrawMoney()
{
$this->assertEquals(0, $this->ba->getBalance());
$this->ba->depositMoney(1);
$this->assertEquals(1, $this->ba->getBalance());
$this->ba->withdrawMoney(1);
$this->assertEquals(0, $this->ba->getBalance());
}
}
?>

コードブロックの無視

どうしてもテストができないコードブロックなどを、 コードカバレッジ解析時に無視させたいこともあるでしょう。 PHPUnit でこれを実現するには、 @codeCoverageIgnoreStart および @codeCoverageIgnoreEnd アノテーションを 例 14.3 のように使用します。

例 14.3: @codeCoverageIgnoreStart および @codeCoverageIgnoreEnd アノテーションの使用法

<?php
class Sample
{
// ...

public function doSomething()
{
if (0) {
// @codeCoverageIgnoreStart
$this->doSomethingElse();
// @codeCoverageIgnoreEnd
}
}

// ...
}
?>

@codeCoverageIgnoreStart アノテーションから @codeCoverageIgnoreEnd アノテーションまでの間の行は、 (たとえ実行されなかったとしても) 実行されたものとみなされ、 強調表示されません。

ファイルのインクルードや除外

デフォルトでは、1 行でもコードが実行されたソースコードファイルはすべて (そしてそのようなファイルのみが) レポートに含められます。 レポートにどのようなソースコードファイルを含めるかを設定するには PHPUnit_Util_Filter API を使用します (表 14.1 を参照ください)。

表14.1 PHPUnit_Util_Filter の API

メソッド 意味
void addDirectoryToFilter(string $directory) あるディレクトリ内でファイル名の最後が .php であるすべてのファイルを (再帰的に) ブラックリストに追加します。
void addDirectoryToFilter(string $directory, string $suffix) あるディレクトリ内でファイル名の最後が $suffix であるすべてのファイルを (再帰的に) ブラックリストに追加します。
void addFileToFilter(string $filename) ファイルをブラックリストに追加します。
void removeDirectoryFromFilter(string $directory) あるディレクトリ内でファイル名の最後が .php であるすべてのファイルを (再帰的に) ブラックリストから削除します。
void removeDirectoryFromFilter(string $directory, string $suffix) あるディレクトリ内でファイル名の最後が $suffix であるすべてのファイルを (再帰的に) ブラックリストから削除します。
void removeFileFromFilter(string $filename) ファイルをブラックリストから削除します。
void addDirectoryToWhitelist(string $directory) あるディレクトリ内でファイル名の最後が .php であるすべてのファイルを (再帰的に) ホワイトリストに追加します。
void addDirectoryToWhitelist(string $directory, string $suffix) あるディレクトリ内でファイル名の最後が $suffix であるすべてのファイルを (再帰的に) ホワイトリストに追加します。
void addFileToWhitelist(string $filename) ファイルをホワイトリストに追加します。
void removeDirectoryFromWhitelist(string $directory) あるディレクトリ内でファイル名の最後が .php であるすべてのファイルを (再帰的に) ホワイトリストから削除します。
void removeDirectoryFromWhitelist(string $directory, string $suffix) あるディレクトリ内でファイル名の最後が $suffix であるすべてのファイルを (再帰的に) ホワイトリストから削除します。
void removeFileFromWhitelist(string $filename) ファイルをホワイトリストから削除します。

ブラックリストには、PHPUnit 自身のソースコードファイルやテストファイルがデフォルトで登録されています。 ホワイトリストが空 (デフォルト) の場合はブラックリストを使用し、 ホワイトリストが空でない場合はホワイトリストを使用します。 ホワイトリストを使用する場合は、そのファイルが実行されるかどうかにかかわらず リスト内のすべてのファイルがコードカバレッジレポートに追加されます。

Prev Next
1. 自動テスト
2. PHPUnit の目標
3. PHPUnit のインストール
4. PHPUnit 用のテストの書き方
データプロバイダ
例外のテスト
PHP のエラーのテスト
5. コマンドラインのテストランナー
6. Fixtures
tearDown() よりも setUp()
バリエーション
Fixture の共有
7. テストの構成
スイートレベルのセットアップ
8. テストケースの拡張
出力内容のテスト
パフォーマンス低下のテスト
9. データベースのテスト
データセット
Flat XML データセット
XML データセット
操作
データベースのテストのコツ
10. 不完全なテスト・テストの省略
不完全なテスト
テストの省略
11. モックオブジェクト
自己シャント
スタブ
12. テストの進め方
開発中のテスト
デバッグ中のテスト
13. テストファーストプログラミング
銀行口座の例
14. コードカバレッジ解析
カバーするメソッドの指定
コードブロックの無視
ファイルのインクルードや除外
15. テストのその他の使用法
アジャイルな文書作成
複数チームでのテスト
16. ログ出力
XML 形式
コードカバレッジ (XML)
JavaScript Object Notation (JSON)
Test Anything Protocol (TAP)
GraphViz マークアップ
テストデータベース
17. 雛形ジェネレータ
アノテーション
18. PHPUnit と Selenium
Selenium RC
PHPUnit_Extensions_SeleniumTestCase
19. 継続的インテグレーション
CruiseControl
phpUnderControl
Apache Maven
20. PHPUnit の実装
21. PHPUnit API
概要
PHPUnit_Framework_Assert
PHPUnit_Framework_Test
PHPUnit_Framework_TestCase
PHPUnit_Framework_TestSuite
PHPUnit_Framework_TestResult
パッケージの構成
22. PHPUnit の拡張
PHPUnit_Framework_TestCase のサブクラスの作成
アサートクラスの作成
PHPUnit_Extensions_TestDecorator のサブクラスの作成
PHPUnit_Framework_Test の実装
PHPUnit_Framework_TestResult のサブクラスの作成
PHPUnit_Framework_TestListener の実装
新しいテストランナーの作成
A. アサーション
B. XML 設定ファイル
テストスイート
グループ
コードカバレッジ対象のファイルの追加や除外
ログ出力
PMD ルール
PHP INI 項目やグローバル変数の設定
C. PHP 4 用の PHPUnit
D. 目次
E. 参考文献
F. 著作権