testing 出力 - PHPUnitで100%のコードカバレッジに到達



カバレッジツール driver (5)

私はプロジェクトのテストスイートを作成していましたが、100%のカバレッジが得られることわかりませんが、コードカバレッジレポートには奇妙なものがあります。明確化。

スクリーンショットを見る:

テストされているメソッドの最後の行はreturnので、最後の行(閉じ括弧のみ)は実行されていないと表示され、その結果、メソッド全体が概要で実行されていないとフラグが付けられます。 (どちらか、または私は正しくレポートを読んでいない)。

完全な方法:

static public function &getDomain($domain = null) {
    $domain = $domain ?: self::domain();

    if (! array_key_exists($domain, self::$domains)) {
        self::$domains[$domain] = new Config();
    }

    return self::$domains[$domain];
}

これには理由がありますか、それとも不具合ですか?

(はい、私はPHPUnit100%コードカバレッジを取得する方法を読んでいますが 、これと似ていますが異なるケースです)。

編集:

報告書に目を通すと、コード内の別の場所にあるswitch文にも同じことが言えます。 だからこの振る舞いは、少なくともある程度まで一貫していますが、私にはそれほど難解ではありません。

Edit2:

私は走っています:PHPUnit 3.6.7、PHP 5.4.0RC5、XDebug 2.2.0-dev、OS X


Answers

まず、100%のコードカバレッジは、 努力するための大きなメトリックです。 それはちょうど常に努力の正気な量で達成可能ではありません、そして、そうすることは常に重要ではありません:)

この問題はxDebugからPHPUnitにこの行は実行可能だが、対象にはならないことを伝えることから来ている。

単純なケースでは、xDebugはその行が到達可能でないことを知ることができるので、100%のコードカバレッジが得られます。

以下の簡単な例を参照してください。

2番目の更新

問題が修正され、 xDebug bugtrackerが新しいバージョンのxDebugをビルドすると、それらの問題は解決します:)

アップデート(php 5.3.xの問題は以下を参照)

PHP 5.4とxDebugのDEVバージョンを実行しているので、それらをインストールしてテストしました。 私はあなたがコメントしたのと同じ出力であなたと同じ問題にぶつかります。

問題がxDebugのphp-code-coverage (phpunitモジュール)に由来するかどうかは100%確信していません。 また、xDebug devの問題かもしれません。

私はphp-code-coverageバグを提出し 、問題がどこから来るのか把握します。

PHP 5.3.xの問題:

より複雑な場合、これは失敗する可能性があります。

私が言うことができるすべてのコードは、「それは私のために働く」( 以下の複雑なサンプル )です。

おそらく、xDebugとPHPUnitのバージョンを更新して、やり直してください。

私はそれが現行バージョンでは失敗するのを見ましたが、クラス全体が時々どのように見えるかによって異なります。

?:演算子やその他の単一行の複数の文を削除することも役に立ちます。

私が知っている限り、これらのケースの多くを避けるために、xDebugに進行中のリファクタリングがあります。 xDebugは一度 "ステートメントのカバレッジ"を提供できるようにしたいと思っています。 今のところ、ここでできることはあまりありません

//@codeCoverageIgnoreStart//@codeCoverageIgnoreEndはこの行を "覆い隠し"ますが、実際には醜いように見えますが、通常は良いより悪いです。

これが起こる別のケースでは、以下の質問と回答を参照してください。

what-to-do-when-project-coding-standards-conflicts-with-unit-test-code-coverage

簡単な例:

<?php
class FooTest extends PHPUnit_Framework_TestCase {
    public function testBar() {
        $x = new Foo();
        $this->assertSame(1, $x->bar());
    }
}

<?php
class Foo {
    public function bar() {
        return 1;
    }
}

次を生成する:

phpunit --coverage-text mep.php 
PHPUnit 3.6.7 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.50Mb

OK (1 test, 1 assertion)

Generating textual code coverage report, this may take a moment.

Code Coverage Report 
  2012-01-10 15:54:56

 Summary: 
  Classes: 100.00% (2/2)
  Methods: 100.00% (1/1)
  Lines:   100.00% (1/1)

Foo
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)

複雑な例:

<?php

require __DIR__ . '/foo.php';

class FooTest extends PHPUnit_Framework_TestCase {

    public function testBar() {
        $this->assertSame('b', Foo::getDomain('a'));
        $this->assertInstanceOf('Config', Foo::getDomain('foo'));
    }
}

<?php

class Foo {
    static $domains = array('a' => 'b');

    static public function &getDomain($domain = null) {
        $domain = $domain ?: self::domain();
        if (! array_key_exists($domain, self::$domains)) {
            self::$domains[$domain] = new Config();
        }
        return self::$domains[$domain];
    }
}

class Config {}

次を生成する:

PHPUnit 3.6.7 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.50Mb

OK (1 test, 2 assertions)

Generating textual code coverage report, this may take a moment.

Code Coverage Report 
  2012-01-10 15:55:55

 Summary: 
  Classes: 100.00% (2/2)
  Methods: 100.00% (1/1)
  Lines:   100.00% (5/5)

Foo
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  5/  5)

switch文のコードカバレッジの問題に関しては、何もしない "default"のcaseを追加するだけで十分にカバーすることができます。


switch文を100%カバレッジにするにはどうすればいいですか?

存在しないケースを送信するテストが少なくとも1つ存在することを確認します。

だから、あなたが持っているなら:

switch ($name) {
    case 'terry':
        return 'blah';
    case 'lucky':
        return 'blahblah';
    case 'gerard':
        return 'blahblah';
}

テストの少なくとも1つが、 terryluckygerardいずれの名前でもないことを確認してください。


ここでの問題の多くは、 "行"の100%実行カバレッジを取得することに対する主張です。 (マネージャーはこのアイデアが好きで、理解できるシンプルなモデルです)。 多くの行は、 "実行可能"(空白、関数宣言、コメント、宣言、 "純粋な構文"、例えばスイッチやクラス宣言の "閉じる"、複数のソース行に分割された複雑な文)

あなたが本当に知りたいのは、「すべての実行可能コードは対象ですか?」 この区別は愚かなように思えますが、解決策につながります。 XDebugは実行される行を行番号で追跡し、XDebugベースのスキームは実行された行の範囲を報告します。 そして、あなたはこのスレッドで議論されている問題を解決します。コードに "私を数えないでください"という注釈を付けること、最後の実行可能なステートメントと同じ行に "}"を入れることなどのklunkyソリューションもあります。それだけではそれを維持することはできません。

実行可能コードを条件付き(コンパイラの人々が「基本ブロック」と呼ぶもの)と呼ぶことができるコード、またはカバレッジトラッキングがそのように行われるコードとして定義すると、コードのレイアウトとばかげたケース単に消える。 このタイプのテストカバレッジツールは、「ブランチカバレッジ」と呼ばれるものを収集し、すべての実行可能コードを実行することによって文字通り100%「ブランチカバレッジ」を取得するか取得できます。 さらに、行内に条件付き( "x?y:z"を使用)または行内に2つの従来の文がある(例えば、

 if  (...)  {   if  (...)  stmt1; else stmt2; stmt3 }

XDebugは行ごとに追跡するので、私はこれを1つの文として扱い、コントロールが実際にテストする5つの部分がある場合には、それがカバレッジになると考えます。

私たちのPHPテストカバレッジツールは、これらのアイデアを実装しています。 特に、return文に続くコードは実行可能ではないことを理解しています。空でない場合は、実行していないことを伝えます。 それはOPの元の問題を消滅させるだけです。 「本物の」カバレッジ番号を得るためのゲームはこれ以上ありません。

すべての選択肢と同様に、時には欠点があります。 私たちのツールには、Windows上でのみ動作するコード計測器コンポーネントがあります。 計測されたPHPコードはどこでも実行でき、処理/表示はプラットフォームに依存しないJavaプログラムによって実行されます。 これは、OPのOSXシステムにとっては厄介なことかもしれません。 instrumenterはNFS対応のファイルシステムでうまく動作するので、PC上でinstrumenterを実行し、OSXファイルを計測することは間違いありません。

この特定の問題は、カバレッジ・ナンバーを押し上げようとしている人によって引き起こされました。 問題は人工的なIMHOであり、人工物を踏んで治すことができます。 より多くのテストを書くことなく数字を押し上げる別の方法があります。それは、重複したコードを探し出して削除することです。 重複を削除した場合、エフェクトテストではコピーされていない1つのコピーをテストしてテストするコードが少なくて済みますので、より多くの番号を取得する方が簡単です。 詳細はこちらをご覧ください。


これを実現する最善の方法の1つは、CodeIgniterのフォーム検証ライブラリを拡張することです。 たとえば、データベース・テーブル・usersフィールドaccess_codeに対して、 access_code_uniqueという名前のカスタム・バリデーターを作成するとします。

application/librariesディレクトリにMY_Form_validation.phpという名前のクラスファイルを作成するだけです。 このメソッドは常にTRUEまたはFALSE返す必要がありFALSE

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class MY_Form_validation extends CI_Form_validation {
    protected $CI;

    public function __construct() {
        parent::__construct();
            // reference to the CodeIgniter super object
        $this->CI =& get_instance();
    }

    public function access_code_unique($access_code, $table_name) {
        $this->CI->form_validation->set_message('access_code_unique', $this->CI->lang->line('access_code_invalid'));

        $where = array (
            'access_code' => $access_code
        );

        $query = $this->CI->db->limit(1)->get_where($table_name, $where);
        return $query->num_rows() === 0;
    }
}

これで、作成した新しいルールを簡単に追加できます

$this->form_validation->set_rules('access_code', $this->lang->line('access_code'), 'trim|xss_clean|access_code_unique[users]'); 




php testing phpunit code-coverage