よく忘れるので自分用のメモ。
何を実現したいか
例えば、以下のような Trait が存在して、 static::deleted()
の Closure も Mockery を使って UnitTest でカバーしたい時の方法。
trait SomeTrait
{
/**
* boot
*/
public static function bootSomeTrait()
{
static::deleted(function ($model) {
$model->someModelsMethod();
});
}
}
どうやって実現するか
以下のようにすると closure 部分も UnitTest でカバーできるようになる。
final class SomeTraitTest extends TestCase
{
public function testSomeTrait()
{
$class = new class {
use SomeTrait;
public static function deleted($closure)
{
$mock = Mockery::mock(stdClass::class);
$mock->shouldReceive('someModelsMethod')->once()->with();
$closure($mock);
}
};
$class::bootSomeTrait();
}
}
anonymous class 内で use SomeTrait
して、 SomeTrait
が用いる public static function deleted($closure)
を anonymous class に定義する。
この anonymous class の引数である $closure
は SomeTrait
の static::deleted(function ($model) {...}
の function 部分が引数なので、 callable となる。
なので、ここで適切に Mockery 等を使って何らかの手続を確認するように書けば良い。
注意点とか
anonymous class(無名クラス)使ってるので、当然 PHP7 以上じゃないとダメ。
laravel で event を登録する処理を書くなら、素直に Observer 使うべきだと思う。 https://laravel.com/docs/5.8/eloquent#observers
ただ、外部のパッケージで便利なやつがあって、それが Trait で実現されてて…かつ、そのパッケージに少しだけオリジナルな処理を追加したい時とかに、 trait ベースで Event 登録が必要になったりする。
あと parent::otherMethod();
とかある場合は、このアプローチは使えない。(anonymous class 使ってるので親が居ないので当然。)