第148回 PHP勉強会@東京のLTで使用したスライドです。
Mockeryを読んでみたよ2023/01/18第148回 PHP勉強会@東京
View Slide
コードリーディングの歴史第146回PHP勉強会■ 柚⼝ ましろう さん第147回PHP勉強会■ y_sone さん
流れにのっていくしかない!! 🌊
> whoami■ 名前: ちひろ/ちろ/前⽥■ Twitter: @chiroruxxxx■ 所属: 東京都⽴産業技術⼤学院⼤学産業技術専攻情報アーキテクチャコース追川PBL■ テーマ: スクラムの理論と実践
Mockery とは■ モック(テストダブル)を作ってくれるライブラリ■ ユニットテストとかで便利
サンプルコード$user = Mockery::mock(User::class);$user->shouldReceive('getFullName')->andReturn('テスト太郎');$decorator = new Decorator();$this->assertSame('** テスト太郎 **',$decorator->decorate($user));
サンプルコード$user = Mockery::mock(User::class);$user->shouldReceive('getFullName')->andReturn('テスト太郎');$decorator = new Decorator();$this->assertSame('** テスト太郎 **',$decorator->decorate($user));モックしたクラスはUserクラス︖
サンプルコード$user = Mockery::mock(User::class);$user->shouldReceive('getFullName')->andReturn('テスト太郎');$decorator = new Decorator();$this->assertSame('** テスト太郎 **',$decorator->decorate($user));モックしたクラスはUserクラス︖コンストラクタで引数が必要だけど︖
サンプルコード$user = Mockery::mock(User::class);$user->shouldReceive('getFullName')->andReturn('テスト太郎');$decorator = new Decorator();$this->assertSame('** テスト太郎 **',$decorator->decorate($user));モックしたクラスはUserクラス︖コンストラクタで引数が必要だけど︖こんなメソッドないけど︖
いったい何者なんだ・・・!!
コードを読んで追っていくぞ 💪
今回の⽬的■ Mockery::mock(User::class)で作成されるクラスが何者なのかを追ってく■ 今回紹介しない話も、ブログに書いています– あしたからがんばる - Mockeryでのモックの作り⽅を調べてみた
コードを読む■ PhpStorm + XDebug で1⾏ずつ状態を確認しながら読める■ 設定がちょっとだけ⾯倒– PHPerKaigi 2023で・・・?
さっそく読んでいきます
クラス定義の読み込み■ ファイルを読み込んでる■ 展開してみると・・・?$code = file_get_contents(__DIR__ . '/../Mock.php');
クラス定義の読み込み$code = 'class Mock implements MockInterface{// ...public function shouldReceive(...$methodNames){// ...';
クラス定義の読み込み$code = 'class Mock implements MockInterface{// ...public function shouldReceive(...$methodNames){// ...';💡 モックでメソッドが使える
クラスの継承■ Userクラスを継承するように書き換えてる$code = str_replace("implements MockInterface","extends ¥¥" . $className . " implements MockInterface",$code);
クラスの継承$code = 'class Mock extends ¥App¥Models¥User implements MockInterface{// ...public function shouldReceive(...$methodNames){// ...';💡 User 型として扱える
クラスのロード■ ええい! eval じゃい!■ ただの⽂字列から実⾏可能な状態にeval("?>" . $definition->getCode());
クラスのロード■ クラスはできた!!インスタンスはまだ作ってないclass Mock extends ¥App¥Models¥User implements MockInterface{// ...public function shouldReceive(...$methodNames){// ...
インスタンスの作成■ リフレクションクラスを使って 💡コンストラクタ実⾏無しでインスタンスを作成■ ・・・⿊魔術だ!!$reflectionClass = $this->getReflectionClass($className);return $reflectionClass->newInstanceWithoutConstructor();
インスタンスの作成
まとめ■ モックしたクラスは User クラス?– User クラスを継承しているのでUser型として扱える■ shouldRecieve なんてメソッドは User クラスにないけど?– User クラスを継承した先で定義しているので使える■ コンストラクタで引数が必要だけど?– リフレクションを使ってコンストラクタ無しで⽣成してる
まとめ■ みんなが使ってるあのライブラリも、蓋を開ければ案外ゴリ押し■ みんなも気軽にゴリ押しでライブラリを作ってみては?