5

保護されたメソッドがパブリック インターフェイスで呼び出されるかどうかをテストしようとしています。

<?php
abstract class SomeClassAbstract
{ 
    abstract public foo();

    public function doStuff() 
    {    
        $this->_protectedMethod();
    }

    protected function _protectedMethod();
    {
        // implementation is irrelevant
    }
}

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testCalled()
    {
        $mock = $this->getMockForAbstractClass('SomeClass');
        $mock->expects($this->once())
             ->method('_protectedMethod');

        $mock->doStuff();
    }
}

私はそれが正しく呼び出されていることを知っていますが、PHPUnitは決して呼び出されないと言います.

メソッドが呼び出されない場合、他の方法でテストすると同じことが起こります。

<?php
abstract class AnotherClassAbstract
{ 
    abstract public foo();

    public function doAnotherStuff() 
    {    
        $this->_loadCache();
    }

    protected function _loadCache();
    {
        // implementation is irrelevant
    }
}

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testCalled()
    {
        $mock = $this->getMockForAbstractClass('AnotherClass');
        $mock->expects($this->once())
             ->method('_loadCache');

        $mock->doAnotherStuff();
    }
}

メソッドは呼び出されますが、PHPUnit はそうではないと言っています。

私が間違っていることは何ですか?

編集 私は自分のメソッドを二重コロンで宣言していませんでした。これは、それがパブリック メソッド (インターフェイス) であることを示すためだけでした。完全なクラス/メソッド宣言に更新されました。

編集 2 抽象クラスでいくつかのメソッドの実装をテストしていると言うべきでした (これを反映するようにコードを編集しました)。クラスをインスタンス化できないので、どうすればこれをテストできますか?

SomeClassSimple代わりに、これを拡張SomeClassAbstractしてテストすることを考えています。それは正しいアプローチですか?

4

2 に答える 2

10

私が持っているバージョンのPHPUnitでは、クラスPHPUnit_Framework_MockObject_MockはPHPを使用しget_class_methodsて、モックされているオブジェクトのインターフェースを判別します。 get_class_methodsパブリックメソッドのみを選択し、保護されたメソッドやプライベートメソッドは選択しません。

これは、xUnitユニットテストの精神に沿ったものです。モックオブジェクトの使用方法に関するPHPUnitドキュメントの例を検討してください。そこで、SUTはSubject、保護されたメソッドを持つnotifyです。ただし、テストされているメソッドはですdoSomethingSubjectブラックボックスとして考えると、それがどのように実装されるかについての詳細は気にしません。ただし、その動作には注意が必要です。具体的には、を呼び出すときに、アタッチされているオブザーバーdoSomethingのメソッドを呼び出す必要があります。updateそこで、サードパーティのオブジェクトをモックし、Observerそのupdateメソッドが呼び出されることを期待します。保護された方法ですが注意してくださいnotifyが実行された場合、テストで明示的に名前が付けられません。これにより、動作が維持されている限り、いつでも実装を自由に変更できます。

あなたの例に戻ります。

class MyTest extends PHPUnit_Framework_TestCase
{
  public function testCalled()
  {
    $mock = $this->getMock('SomeClass');
    $mock->expects($this->once())
         ->method('_protectedMethod');

    $mock->doStuff();
  }
}

ここでは、testCalledメソッドはテスト対象システム(SUT)のインスタンスを作成しません。これはSomeClassになります。doStuffSomeClassのモックのバージョンは何もしません。特に、を呼び出しません_protectedMethod

于 2009-11-05T14:37:33.763 に答える
3

その関数をモックアウトしたいことをPHPUnitに伝える必要があるようです。

$mock = $this->getMock('SomeClass',
                        array('_protectedMethod'));
$mock->expects($this->once())
     ->method('_protectedMethod');

$mock->doStuff();
于 2010-06-11T03:37:06.960 に答える