0

プライベート/保護されたメソッドのテストに関して疑問があります。これは、あらゆるプラットフォームの単体テストに関する一般的な質問です。しかし、私は phpunit を使用して、php を単体テストするためのプラットフォームを使用しています。

プライベート/保護されたメソッドをテストする必要がありますか? この質問に対する受け入れられた回答は、通常はすべきではないと言っています。その答えから:

通常、プライベートおよび保護されたメソッドを直接テストまたはモックしません。

テストしたいのは、クラスのパブリック API です。それ以外はすべてクラスの実装の詳細であり、変更してもテストを「中断」しないことを示しています。

しかし同時に、非常に多くの質問の他の回答は、それらをテストする方法を提供します(これらの回答は、プライベート/保護されたメソッドをテストする必要があることを意味すると思います。テストする必要がある、またはテストしないでください)。

理由を添えて教えてください。ありがとうございました。

4

3 に答える 3

1

プライベート メソッドと保護されたメソッドは、テスト対象のコードの実装の詳細であり、テストする必要はありません。テストは、コードが何をするべきかを教えてくれます。プライベート メソッドとプロテクト メソッドをテストすると、コードがこれまでに行っていることを「どのように」実行することになっているのかがわかり始めます。

一部のコードの再利用が見つかり、テストが失敗したためにクラスを変更していくつかのプライベート メソッドを追加すると、一部の機能を変更し、そのテスト ケースを修正する必要があるためであることがわかります。プライベート メソッドとプロテクト メソッドのテストがあり、同じことを行う場合、テストが正当な理由で失敗しているのか、それともリファクタリングによるものなのかを確認する必要があります。プライベート メソッドとプロテクト メソッドは、クラスのパブリック インターフェイスのテストによってカバーされ、独自のテストは必要ありません。

何かを「できる」からといって、何かを「しなければならない」とは限りません。

テスト中は、テスト対象のシステムをブラック ボックスと見なします。私はそれに何かを与え、何かが起こることを期待しています。内部で何が起こっているかは気にしません。重要なのは、正しい出力が与えられることだけです。

複雑な内部関数はコードのにおいです。おそらく、私のクラスがやりすぎていて、内部に別のクラスが隠れている可能性があります。

于 2013-07-30T14:00:17.117 に答える
1

私に関しては、プライベート/保護されたメンバーの複雑さに依存します。

たとえば、プライベート メソッドFunc1 () およびFunc2 () があり、複雑な計算や、多くの入力パラメーターを持つアルゴリズムがあるとします。そして、それらの両方を使用するパブリック API があります。また、一部のデータではFunc1 () が壊れて正しくないデータを返しますが、Func2 () での処理中に、このデータは何らかの形で正しい結果に変換されます (他の問題の結果として)。パブリック API メソッドの合計結果は正しくなります。つまり、 Func1とFunc2は正しくありませんが、API は何らかの形で正しいものを返します。そして、あなたはそれをテストします、そしてそれは大丈夫です.

誰かにコードを渡したところ、彼/彼女は Func3 () と、 Func1 () とFunc3 () を使用するもう 1 つのパブリック API メソッドを作成し、この API メソッドの単体テストは失敗しました。その理由がFunc1にあることを突き止めるのに、彼/彼女はどのくらいの時間を費やしますか? Func1が修正されると、以前のテストでFunc2が失敗することになります...これはまったく良くありません。

したがって、私見では、プライベート/保護されたメソッドが複雑で (多くのコードまたは明らかでないアルゴの使用)、再利用可能である場合は、それらをテストする必要があります。もちろん、a + b を返すプライベート メソッドや、デバッグ ログ レコードを書き込むために、100 個の単体テストを作成する必要はありません。

私の答えがあなたに役立つことを願っています! よろしく、ミハイル。

于 2013-07-30T07:42:06.620 に答える
0

Private/Protected メソッドのテストは、それらがどこでどのようにアクセスされるか、および何がテストされるかに依存すると思います。

共通コードの再利用可能なライブラリを構築している場合、これらのクラス内のプライベート メソッドと保護されたメソッドは、ライブラリ テスト ケース内でテストされます。これらのテストにより、下位レベルのコードが機能することが保証されるため、ライブラリを信頼することができます。

ここで、このライブラリにアクセスするビジネス アプリケーションを作成するときは、ビジネス アプリケーションのテストでモックされるため、ライブラリ オブジェクトのテストは作成しません。ライブラリ テストでライブラリが機能することが示され、次にビジネス アプリケーション テストでアプリケーションが機能することが示されます。

ビジネス アプリケーションは、ライブラリのプライベート/保護されたメソッドをテストしようとはしません。これは、(外部ライブラリや Web サービスと同様に) 私が知らないコードのブラック ボックスであると考えているためです。ただし、ビジネス アプリケーションのプライベート メソッドと保護されたメソッドをビジネス アプリケーションのテスト スイートでテストし、メソッド/関数が正常に動作していることを確認します。

例として、次のビジネス クラスを想定します (機能ではなく、考えを伝えるために非常に簡単に説明します)。

<?php
class ACCOUNTS
{
    protected GetEstimation()
    {
        ...
        return $CalculatedValue;
    }
}

class CUSTOMER_ACCOUNT extends ACCOUNTS
{
    protected GetEstimation()
    {
        $BaseEstimation = parent::GetEstimation();
        ...
        return $NewCalculatedValue
    }
}

class RESELLER_ACCOUNT extends ACCOUNTS
{
    protected GetEstimation()
    {
        ...
        return $ResellerCalculatedValue; // Note: No call to parent
    }
}
?>

この例では、返されるさまざまな値があります。オーバーライドできるように Protected 関数が使用されており、親クラスの機能に依存する必要はありません。この例では、これらすべてのクラスが使用時に適切な値を返すことをテストしたいと思います。

基本的な ACCOUNTS クラスは、クラスの値に基づいて計算を行った後、Estimation を返す必要があります。原則として、値を設定して戻り値をテストするだけです。

<?php
class ACCOUNTSTest extends PHPUnit_Framework_TestCase
{
    protected $Accounts;

    protected function setUp()
    {
        $this->Accounts = new ACCOUNTS();
    }

    public function testEstimationHome()
    {
        $this->Accounts->InternalValue1 = 1;
        $this->Accounts->InternalValue2 = 10;
        $this->Accounts->InternalValue3 = 100;
        $this->assertEquals(523, $this->Accounts->GetEstimation(), 'Test Home Account with values 1, 10, 1000');
    }

    public function testEstimationHome2()
    {
        $this->Accounts->InternalValue1 = 5;
        $this->Accounts->InternalValue2 = 2;
        $this->Accounts->InternalValue3 = 10;
        $this->assertEquals(253, $this->Accounts->GetEstimation(), 'Test Home Account with values 5, 2, 10');
    }

    protected function tearDown()
    {
        unset($this->Accounts);
    }
}
?>

これらのテストにより、ACCOUNTS->GetEstimation() が正しく機能していることを確認できるようになりました。次に、CUSTOMER_ACCOUNT をテストし、同様のテストを行って、クラスが正しく計算されていることを確認します。

はい、基本クラスが変更された場合、ACCOUNTS->GetEstimation() が変更されたため、CUSTOMER_ACCOUNT のテストを更新する必要があるかもしれませんが、基本クラスがまだ正しく返されていることを確認する追加のチェックもあります。

別の方法として、この構造を変更し、依存性注入を使用して特定の情報 (ACCOUNTS) を提供し、親の推定値が常に 523 である場合に、このクラスが適切な値を返すようにすることもできます。ACCOUNTS が返された推定値を変更しても、このクラスには問題がない場合 (このクラスは値を追加しているだけかもしれません)、テストを分離して心配する必要はありません。

このアップデートが、私が言っていることを説明するのに役立つことを願っています.

于 2013-07-30T12:48:44.687 に答える