web-dev-qa-db-ja.com

PHPUnit:非公開変数に対してアサーションを行う

プライベートプロパティと関連するパブリックゲッターおよびセッターを持つクラスがあるとします。 PHPUnitを使用して、セッターが使用された後にプロパティが正しい値を取得するか、ゲッターが正しいプロパティを返すかをテストしたいと思います。

もちろん、getterを使用してセッターをテストし、オブジェクトが正しい値を格納していることを確認できます。ただし、これはプライベートプロパティが設定されていることを保証するものではありません。

次のクラスがあったとしましょう。プロパティ、ゲッター、セッターを作成しました。しかし、私はプロパティ名にタイプミスを作ったので、ゲッターとセッターは、操作するためのプロパティを実際には操作しません

class SomeClass
{
    private 
        $mane = NULL; // Was supposed to be $name but got fat-fingered!

    public function getName ()
    {
        return ($this -> name);
    }

    public function setName ($newName)
    {
        $this -> name = $newName;
        return ($this);
    }
}

次のテストを実行すると

public function testSetName ()
{
    $this -> object -> setName ('Gerald');
    $this -> assertTrue ($this -> object -> getName () == 'Gerald');
}

パスを取得します。しかし、私が望まない非常に悪いことが実際に起こった。 setName()が呼び出されると、クラスに新しいプロパティが作成され、私のプライベートプロパティが持っていると思った名前が付けられます。セッターが作成するプロパティだけがパブリックです。私は次のコードでそれを示すことができます:

$a  = new SomeClass;

$a -> setName('gerald');
var_dump ($a -> getName ());
var_dump ($a -> name);

それは出力します:

string(6)「ジェラルド」

string(6)「ジェラルド」

PHPUnitからプライベートプロパティにアクセスして、取得および設定されていると思うプロパティが実際に取得および設定されていることを確認するテストを記述できる方法はありますか?

または、テスト中のオブジェクトのプライベート状態にアクセスしようとせずに、このような問題を検出するためにテストで他に行う必要があることはありますか?

25
GordonM

プロパティのテストについては、プライベートメソッドのテストについて説明するのと同じ議論をします。

You usually don't want to do this

観察可能な動作をテストすることです。

すべてのプロパティの名前を変更するか、それらを配列に格納することにした場合、テストをまったく適応させる必要はありません。テストですべてがまだ機能することを通知する必要がありますchangeテストがすべて機能することを確認する必要がある場合、テストの変更でエラーが発生する可能性があるため、すべての利点が失われます。

つまり、全体として、テストスイートの価値を失うことになります。


Get/setの組み合わせをテストするだけで十分ですが、通常、すべてのsetterにgetterが必要なわけではなく、テストのためにそれらを作成するだけではいいことではありません。

通常、いくつかのものを設定してから、メソッドにDO(動作)を指示します。そのためのテスト(クラスが行うべきことを行うこと)は、テストに最適なオプションであり、プロパティのテストを不必要にする必要があります。


あなたが本当にそれをしたいなら、PHPリフレクションAPIにsetAccessible機能がありますが、これが望ましいと思う例を作ることはできません

このようなバグ/問題をキャッチするために未使用のプロパティを見つける:

PHP Mess Detector として UnusedPrivateField Rule

class Something
{
    private static $FOO = 2; // Unused
    private $i = 5; // Unused
    private $j = 6;
    public function addOne()
    {
        return $this->j++;
    }
}

変数にはアクセスされないため、2つの警告が生成されます

23
edorian

Assert::assertAttributeEquals('value', 'propertyName', $object)を使用することもできます。

https://github.com/sebastianbergmann/phpunit/blob/3.7/PHPUnit/Framework/Assert.php#L49 を参照してください

39
Gildas

一つだけ指摘したいことがあります。プライベートフィールドのことを少し忘れて、クラスのクライアントが気にしていることに焦点を当てましょう。この場合、クラスはコントラクトを公開しますゲッターとセッターを介して)名前を変更および取得する機能。期待される機能はシンプルです:

  • setNameで名前を"Gerald"に設定すると、getNameを呼び出したときに"Gerald"が取得されると期待しています

それで全部です。クライアントは内部の実装を気にしません(まあ、いけません!)。プライベートフィールド名、ハッシュセット、または動的に生成されたコードを介して呼び出されたWebサービスを使用したかどうかは、クライアントにとっては問題ではありません。ユーザーの観点から見ると、現在発生しているbugはバグではありません。

PHPUnitでプライベート変数をテストできるかどうか-わかりません。しかし、単体テストの観点からは、そうすべきではありません。

---(編集(コメントに応じて):

内部状態の暴露の可能性に関する懸念を理解しましたが、ユニットテストはそれに対処するための適切なツールではないと思います。 somethingsomething else計画されていませんでした。単体テストは決して万人を治すものではなく、そのように使用すべきではありません。

3
k.m

テストでプライベートにアクセスすることは一般的に避けたいが、必要な場合は リフレクションを使用してプロパティを読み書きする ができることを他の人にも同意します。

2
David Harkness