29

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

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

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

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 からプライベート プロパティにアクセスして、取得および設定されていると思われるプロパティが実際に取得および設定されていることを確認するテストを作成する方法はありますか?

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

4

4 に答える 4

25

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

You usually don't want to do this

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

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

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


get / setの組み合わせをテストするだけで十分ですが、通常、すべてのセッターにゲッターがあるとは限りません。テスト用にそれらを作成するだけでは、良いことではありません。

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


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

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

PHPの混乱検出器としてUnusedPrivateField Rule

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

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

于 2012-01-19T16:24:25.337 に答える
3

一つだけ指摘したい。プライベート フィールドのことはしばらく忘れて、クラスのクライアントが関心を持っていることに注目しましょう。この場合、クラスはコントラクトを公開します。これは、(ゲッターとセッターを介して) 名前を変更および取得する機能です。期待される機能は単純です。

  • setNametoでname を設定すると、呼び出したときに"Gerald"取得することが期待されます"Gerald"getName

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

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

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

内部状態が公開される可能性についての懸念は理解していますが、単体テストはそれに対処するための適切なツールではないと思います。何かが計画されていなかったのことを行う可能性があるという多くの可能なシナリオを思いつくことができます. 単体テストは決して万能ではなく、単体テストとして使用すべきではありません。

于 2012-01-19T16:06:43.160 に答える
2

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

于 2012-01-19T19:12:38.393 に答える