web-dev-qa-db-ja.com

PHPUnitで、親メソッドをモックするにはどうすればよいですか?

同じ名前の親メソッドを呼び出すクラスメソッドをテストしたいと思います。これを行う方法はありますか?

class Parent {

    function foo() {
        echo 'bar';
    }
}

class Child {

    function foo() {
            $foo = parent::foo();
            return $foo;
    }
}

class ChildTest extend PHPUnit_TestCase {

    function testFoo() {
        $mock = $this->getMock('Child', array('foo'));

        //how do i mock parent methods and simulate responses?
    }
}
25
james

サブジェクトアンダーテスト(SUT)でメソッドをモックまたはスタブしないでください。 SUTの親でメソッドをモックまたはスタブする必要があると思われる場合は、継承ではなく集約を使用すべきだった可能性があります。

あなたは被検者の依存関係を嘲笑します。これは、SUTが作業を行うために必要な他のオブジェクトを意味します。

20
Gordon

私にとって有効なアプローチは、子クラスの親呼び出しへのラップを実装し、最後にそれらのラップをモックすることです。

コードを変更しました:

class Parent {

    function foo() {
        echo 'bar';
    }
}

class Child {

    function foo() {
            $foo = $this->parentFooCall();
            return $foo;
    }
    function parentFooCall() {
            return parent::foo();
    }
}

class ChildTest extend PHPUnit_TestCase {

    function testFoo() {
        $mock = $this->getMock('Child', array('foo', 'parentFooCall'));

        //how do i mock parent methods and simulate responses?
    }
 }
8
user1029767

これが私がそれをした方法です、これが正しいかどうかはわかりませんが、それは機能します:

class parentClass {
    public function whatever() {
        $this->doSomething();
    }
}

class childClass extends parentClass {
    public $variable;
    public function subjectUnderTest() {
        $this->variable = 'whocares';
        parent::whatever();
    }
}

今テストで私はします:

public function testSubjectUnderTest() {
    $ChildClass = $this->getMock('childClass', array('doSomething'))
    $ChildClass->expects($this->once())
               ->method('doSomething');
    $ChildClass->subjectUnderTest();
    $this->assertEquals('whocares', $ChildClass->variable);
}

何?

ここでの私の推論は、私が本当にテストしたいのは、変数が設定されたかどうかだけだということです。親メソッドで何が起こるかはあまり気にしませんが、親メソッドが呼び出されるのを防ぐことはできないので、親メソッドの依存メソッドをモックします。

今、先に進んで、私が間違っていると言ってください:)

4
Dallas Caley

@Gordonに完全に同意します。私は同じ問題を抱えていますが、いくつかのトリッキーな概念を試しました。

私のシナリオは

class Parent { // Actual-Parent Class
    function save() {
        // do something
        return $this
    }
}

class Child extends Parent {
   // Subject under test
    function save() {
          // do something
          return parent::save();
    }
}

同じ名前「Parent」で別の親クラスを作成し、スタブとして扱い、スタブクラス(親)を含め、実際の親を無視します(自動ロードに設定された実際の親クラスとスタブ親を含める必要があります)

class Parent { //Stub-Parent class
    function save() {
        return $this
    }
}

ここで、Childクラスのモックオブジェクトを(Mock-builderを介して)作成し、assertSameの終わりでテストケースを完了します。 :-)

$this->assertSame($mock, $mock->save());
2
Manish Trivedi

私の意見では、満足のいく解決策は、テスト対象のクラスから継承するクラスを作成し、別の実装を提供するメソッドの実装をオーバーライドすることです。これには欠点があります。たとえば、常に機能するとは限りません。すでにオーバーライドされているメソッドとプライベートメソッドの場合。

class Parent
{
    function bar()
    {
        echo 'bar';
    }
}

class Child extends Parent
{
    function foo()
    {
        parent::bar();
        echo 'foo';
    }
}

class mockChild extends Child
{
    function bar()
    {
        echo 'baz';
    }
}

class ChildTest extends PHPUnit_TestCase 
{
    function testFoo() {
        $sut = new mockChild();
        $sut->foo();
    }
} 
0