8

私はここで、プライベートメソッドとプロパティをテストするためのユニットテストの使用に関するいくつかの質問を読んでいます。私は単体テストに不慣れで、テストがプライベート/保護されたプロパティとメソッドにアクセスできるように、試しているメソッドに入力したいと思います。

私が取り組んでいたテストでは、特定のパラメーターをオブジェクトに渡すと、プロパティが設定されることを確認したかったのです。単体テストの教育にSimpleTestを使用していますが、テスト方法は次のとおりです。

function test__Construction_Should_Properly_Set_Tables() {
  $cv = new CVObject( array( 'tables' => $this->standardTableDef ) );
  $tables = $cv->tables;
  $this->assertEqual( $tables, $this->standardTableDef );
}

次に、CVObjectに__getメソッドを次のように記述しました。

function __get( $name ) {
  $trace = debug_backtrace();
  $caller = $trace[1];
  $inTesting = preg_match( '/simpletest/', $caller['file'] );

  if ( $inTesting ) {
    return $this->$name;
  } else {
    trigger_error( 'Cannot access protected property CVObject::$' .
                     $name . ' in ' . $trace[0]['file'] . ' on line ' .
                     $trace[0]['line'],
                    E_USER_NOTICE );
  }
}

これに関する私の考えは、呼び出し元のファイルがSimpleTestからのものである場合は、先に進んでプロパティをテスト目的で使用できるようにしますが、そうでない場合はエラーをトリガーします。これにより、プロパティをプライベートに保つことができますが、テストで使用することができます。これは、これから作成する特定のプライベートメソッドでより重要になります。

だから、私の質問は、私はここで本当に悪いものを見逃しているので、このテクニックを避けるべきですか?

4

4 に答える 4

11

行き詰まって、完全なテストを可能にするためにプライベート/保護されたプロパティにアクセスする必要がある場合は、少なくともテストまたはテスト フレームワークにアクセスを可能にするコードを配置してください。運用コードにテスト専用コードを埋め込むと、a) 設計が複雑になり、b) テストが必要なコードがさらに追加され、c) 運用環境ではコードが異なる方法で実行されることになります。

保護されたプロパティには Ken のサブクラス メソッドを使用できますが、プライベートにアクセスする必要があり、PHP 5.3.2 以降を使用している場合は、リフレクションを使用できます。

function test__Construction_Should_Properly_Set_Tables() {
    $cv = new CVObject( array( 'tables' => $this->standardTableDef ) );
    $tables = self::getPrivate($cv, 'tables');
    $this->assertEqual( $tables, $this->standardTableDef );
}

static function getPrivate($object, $property) {
    $reflector = new ReflectionProperty(get_class($object), $property);
    $reflector->setAccessible(true);
    return $reflector->getValue($object);
}

スーパークラスから継承されたプロパティについて書かれたとおりに動作しないことに注意してください。ただしgetPrivate()、階層をループして宣言クラスを見つけるのはそれほど難しくありません。

于 2011-02-20T00:28:06.553 に答える
0

コンポーネントをテストするときは、そのインターフェース (入力、出力、例外) のみをテストする必要があり、それが内部実装であることを考慮したり、認識したりすることさえありません (1 人のプログラマーがテスト ケースを作成し、もう 1 人が実装を行う場合はなおさらです。XP と TDD を参照してください)。テクニック)。したがって、テストする必要があるのは public メソッドだけです。

プライベート (ヘルパー) メソッドが正しく記述されていることを確認するには、コード カバレッジ アナライザー ( PHP のコード カバレッジ ツールを確認してください) を使用し、テスト ケースでできるだけ多くのコードをカバーします。

あなたのソリューションは、メンテナンスの悪夢を保証します。テスト ケースとコンポーネントの実装は、いかなる方法でも結合されるべきではありません。

于 2011-02-19T10:40:25.400 に答える
0

手っ取り早い解決策は、(プライベートではなく) 保護されたメソッドを使用し、テスト対象のメソッドをパブリックにするラッパーを使用してテストすることです。

class Foo
{
    protected function bar(){} // should really be private but protected will do
}

class FooTestWrapper extends Foo
{
    public function bar{} { return parent::bar(); } // this is testable
}

しかし、ljank が指摘しているように、プライベート メソッド/実装のテストはメンテナンスの悪夢になる可能性があります。これはおそらく、他のクラスに任せるべき作業を行っていることを意味します。

于 2011-02-19T14:04:29.463 に答える
0

一般的に言えば、コードにはテストのためだけの機能を含めるべきではありません。また、プライベート/保護されたメソッドをテストすることが良い方法であるかどうかについては議論の余地がありますが、特定のプライベート/保護されたメソッドを分離してテストしたい場合があります。


Netsilik /BaseTestCase (MIT ライセンス) を使用すると、プライベート変数を設定/取得し、プライベートまたは保護された関数を呼び出すことができます。

composer require netsilik/base-test-case


テストするクラス:

<?php
namespace App;

class Foo
{
    private $bar;

    protected function setBar(string $bar)
    {
        $this->bar = $bar;
    }
}

単体テスト:

class MyTestCase extends \Netsilik\Testing\BaseTestCase
{
    public function test_whenProtectedMethodCalled_thenPrivateMemberSet()
    {
        $foo = new Foo();

        self::callInaccessibleMethod($foo, 'setBar', 'abc');

        self::assertEquals('abc', self::getInaccessibleProperty($foo, 'bar'));
    }
}

お役に立てれば。

于 2019-08-14T09:46:37.793 に答える