7

コールバック内で $this を使用して、phpunit でモック化されたクラスの保護されたプロパティを取得できますか? または、それを達成する他の方法はありますか?

 $mock = $this->getMock('A', array('foo'));
 $mock->expects($this->any())->method('foo')->will(
     $this->returnCallback(function() {
         return $this->bar;
 }));

これは、モック オブジェクトの注入を検討している場合に非常に役立ちます。クラスには他のクラスへのハードコードされた依存関係がある場合がありますが、ハードコードされたオブジェクトの代わりに理論的にモックしてモックオブジェクトを作成できるメソッドで作成します。他の例を見てください。

class A {
  protected $bar = "bar";

  public function foo () {
    $b = new B();
    return $b->fizz($this->bar);
  }
}

class B {
  public function fizz ($buzz) {
    return $buzz;
  }
}

しかし、クラス B が何か悪いことをして、それをモックに置き換えたいとしましょう。

 $mockB = $this->getMock('B');
 // (...) - and probably mock other things
 $mockA = $this->getMock('A', array('foo'));
 $mockA->expects($this->any())->method('foo')->will(
     $this->returnCallback(function() use ($mockB) {
         return $mockB->fizz($this->bar);
 }));

これは何とか達成可能ですか?

もちろん、驚くことではありませんが、現在、上記のようにするとエラーが発生します。

PHP Fatal error:  Using $this when not in object context in (...)

キーワードを使用しuseて、親スコープから $mockA を継承できます。

 $mockB = $this->getMock('B');
 // (...) - and probably mock other things
 $mockA = $this->getMock('A', array('foo'));
 $mockA->expects($this->any())->method('foo')->will(
     $this->returnCallback(function() use ($mockA, $mockB) {
         return $mockB->fizz($mockA->bar);
 }));

しかし、この方法で bar に public としてアクセスしようとすると、次のようになります。

PHP Fatal error:  Cannot access protected property (...)
4

4 に答える 4

7

他の回答が指摘しているように$this、PHP 5.4 以降の Closures で使用できます。あまり知られていない事実として、クロージャを任意のオブジェクトにバインドして、実際にそのプライベート プロパティにアクセスできるようにすることができます。必要なメソッドは、異なるコンテキストを持つ新しいクロージャーbindTo()を返すです。

$cb = function() {
  return $this->bar;
};
$cb = $cb->bindTo($mockA);

またはより正確には、例は次のようになります。

 $mockB = $this->getMock('B');
 // (...) - and probably mock other things
 $mockA = $this->getMock('A', array('foo'));
 $fooCallback = function() use (&$mockB) {
     return $mockB->fizz($this->bar);
 };
 $mockA->expects($this->any())->method('foo')->will(
     $this->returnCallback($fooCallback->bindTo($mockA)));
于 2013-02-10T22:15:57.067 に答える
1

dev-null-dwellerが指摘しているように、PHP 5.4では、メソッドで通常作業している場合と同じように、クロージャ内で$thisを使用できます。

5.3では、次のようにしてこの動作を模倣できます。

public function getCallback(B $b) {
    $self = $this;
    return function() use($b, $self) { 
        return $b->fizz($self->bar);
    };
}
于 2013-02-10T19:45:21.053 に答える
0

PHP 5.4以降$this、クロージャーで使用できますが、これらの保護されたプロパティを含むオブジェクトからこのコールバックを返す必要があります:

class A {
    protected $bar = "bar";

    public function foo () {
        $b = new B();
        return $b->fizz($this->bar);
    }

    public function getCallback(B $b) {
        return function() use($b) { 
            return $b->fizz($this->bar);
        };
    }
}

class B {
    public function fizz ($buzz) {
        return $buzz;
    }
}

$mockA = new A;
$mockB = new B;

$callBack = $mockA->getCallback($mockB);
var_dump($callBack() === $mockA->foo());

ただし、保護されたプロパティの値を取得する必要がある場合は、パブリック getter を定義する必要があります。このようにして、テストはphp 5.3でも機能します

于 2013-02-10T11:13:37.733 に答える