オブジェクトの振舞を明確化するためのモックPHPメンターズ/日本Symfonyユーザー会後藤 秀宣 @hidenorigoto1Symfony勉強会 #6126݄30༵
View Slide
後藤秀宣(ごとうひでのり)PHPメンターズ2126݄30༵
後藤秀宣(ごとうひでのり)PHPメンターズ• Symfonyユーザー会2126݄30༵
後藤秀宣(ごとうひでのり)PHPメンターズ• Symfonyユーザー会• Symfony Midnight2126݄30༵
後藤秀宣(ごとうひでのり)PHPメンターズ• Symfonyユーザー会• Symfony Midnight• 翻訳温泉ツアー2126݄30༵
後藤秀宣(ごとうひでのり)PHPメンターズ• Symfonyユーザー会• Symfony Midnight• 翻訳温泉ツアー• WEB+DB PRESS2126݄30༵
3WEB+DB PRESSvol. 69126݄30༵
4WEB+DB PRESS vol.70126݄30༵
4WEB+DB PRESS vol.70• オブジェクト指向設計の視点から見たモックフレームワークの使い方(Phake、Mockery)126݄30༵
何の話をするの?5126݄30༵
何の話をするの?• ソフトウェアテスト寄りの話ではありません5126݄30༵
何の話をするの?• ソフトウェアテスト寄りの話ではありません• オブジェクト指向設計寄りの話です5126݄30༵
何の話をするの?• ソフトウェアテスト寄りの話ではありません• オブジェクト指向設計寄りの話です• Symfonyのテストコードを例に話します。Symfonyのテストコードを読めるようになります5126݄30༵
モックオブジェクトとは?6126݄30༵
モックオブジェクトとは?• モックオブジェクト6126݄30༵
モックオブジェクトとは?• モックオブジェクト• テストダブルの1つ6126݄30༵
モックオブジェクトとは?• モックオブジェクト• テストダブルの1つ• テストの時に使う、代理オブジェクト6126݄30༵
モックオブジェクトとは?• モックオブジェクト• テストダブルの1つ• テストの時に使う、代理オブジェクト• テストコード側からメソッドの挙動などを動的に定義(置き換え)6126݄30༵
モックオブジェクトとは?• モックオブジェクト• テストダブルの1つ• テストの時に使う、代理オブジェクト• テストコード側からメソッドの挙動などを動的に定義(置き換え)• オブジェクトのコラボレーションを検証できる6126݄30༵
環境7126݄30༵
環境• PHPUnitに同梱されたもの7126݄30༵
環境• PHPUnitに同梱されたもの• PHPUnit_MockObject7126݄30༵
環境• PHPUnitに同梱されたもの• PHPUnit_MockObject• PhakeやMockery(別のライブラリ)をPHPUnitと組み合わせて利用することも可7126݄30༵
環境• PHPUnitに同梱されたもの• PHPUnit_MockObject• PhakeやMockery(別のライブラリ)をPHPUnitと組み合わせて利用することも可• 可読性が高いDSLを提供7126݄30༵
PHPUnit_MockObject8126݄30༵
PHPUnit_MockObject• モックを生成8126݄30༵
PHPUnit_MockObject• モックを生成• getMock()8126݄30༵
PHPUnit_MockObject• モックを生成• getMock()• getMockBuilder()8126݄30༵
PHPUnit_MockObject• モックを生成• getMock()• getMockBuilder()• disableOriginalConstructor()8126݄30༵
PHPUnit_MockObject• モックを生成• getMock()• getMockBuilder()• disableOriginalConstructor()• エクスペクテーション定義8126݄30༵
PHPUnit_MockObject• モックを生成• getMock()• getMockBuilder()• disableOriginalConstructor()• エクスペクテーション定義• expects()8126݄30༵
PHPUnit_MockObject• モックを生成• getMock()• getMockBuilder()• disableOriginalConstructor()• エクスペクテーション定義• expects()• method()8126݄30༵
PHPUnit_MockObject• モックを生成• getMock()• getMockBuilder()• disableOriginalConstructor()• エクスペクテーション定義• expects()• method()• will()8126݄30༵
Symfonyのテストコード• 例:HttpKernelコンポーネントのKernelクラスのテストコード9126݄30༵
10126݄30༵
11bootは()バンドルとコンテナを初期化する126݄30༵
テスト対象をモック化• これは特殊パターン• 通常はテスト対象オブジェクトはモックにしない• テスト対象と同一オブジェクトのメソッド呼び出しを検証する必要があったため、テスト対象そのものをモック化している。• Phake等でいうパーシャルモック• getMockBuilder()でモック化した後、必要なメソッドをsetMethods()で指定。その後expects()でエクスペクテーションを定義。12126݄30༵
13モックを使って• カーネルのboot()メソッド呼び出し時に、必ず呼び出されるメソッドをテストしている126݄30༵
13モックを使って• カーネルのboot()メソッド呼び出し時に、必ず呼び出されるメソッドをテストしているboot()メソッドの振舞をテストしている126݄30༵
通常パターン• HttpKernelコンポーネントのKernelクラスのテストコード14126݄30༵
15126݄30༵
16bootは()バンドルにコンテナをセットするモック生成コラボレーション126݄30༵
17モックを使って• カーネルのboot()メソッドにより、関連しているバンドルオブジェクトのsetContainer()が呼ばれることをテストしている126݄30༵
17モックを使って• カーネルのboot()メソッドにより、関連しているバンドルオブジェクトのsetContainer()が呼ばれることをテストしている関連オブジェクトとのインタラクションを検証している126݄30༵
関連(隣接)オブジェクト18126݄30༵
19関連(隣接)オブジェクト126݄30༵
19関連(隣接)オブジェクト• 対象オブジェクトと直接関連を持つオブジェクト126݄30༵
19関連(隣接)オブジェクト• 対象オブジェクトと直接関連を持つオブジェクト• 通常、テストコードでモック化するのは隣接オブジェクトのみ126݄30༵
19関連(隣接)オブジェクト• 対象オブジェクトと直接関連を持つオブジェクト• 通常、テストコードでモック化するのは隣接オブジェクトのみ• 隣接していないオブジェクトのモックを作る必要がある場合、何か問題がある兆候126݄30༵
20ロール、責務、コラボレーション126݄30༵
20ロール、責務、コラボレーション• 責務駆動設計(オブジェクト指向設計)126݄30༵
20ロール、責務、コラボレーション• 責務駆動設計(オブジェクト指向設計)• 責務とコラボレーションを中心にクラスを設計していく手法。126݄30༵
20ロール、責務、コラボレーション• 責務駆動設計(オブジェクト指向設計)• 責務とコラボレーションを中心にクラスを設計していく手法。• どのクラスにどの責務を割り当てるのか?126݄30༵
20ロール、責務、コラボレーション• 責務駆動設計(オブジェクト指向設計)• 責務とコラボレーションを中心にクラスを設計していく手法。• どのクラスにどの責務を割り当てるのか?• CRCカードによるクラスの発見、ロールステレオタイプによる基本分類126݄30༵
Kernelの責務21126݄30༵
Kernelの責務• テストコード(KernelTest.php)を見ることで責務・振舞が分かる21126݄30༵
Kernelの責務• テストコード(KernelTest.php)を見ることで責務・振舞が分かる• bootは()バンドルとコンテナを初期化する21126݄30༵
Kernelの責務• テストコード(KernelTest.php)を見ることで責務・振舞が分かる• bootは()バンドルとコンテナを初期化する• bootは()バンドルにコンテナをセットする21126݄30༵
Kernelの責務• テストコード(KernelTest.php)を見ることで責務・振舞が分かる• bootは()バンドルとコンテナを初期化する• bootは()バンドルにコンテナをセットする• shutdown()はすべてのバンドルのshutdown()を呼び出す21126݄30༵
Kernelの責務• テストコード(KernelTest.php)を見ることで責務・振舞が分かる• bootは()バンドルとコンテナを初期化する• bootは()バンドルにコンテナをセットする• shutdown()はすべてのバンドルのshutdown()を呼び出す• etc21126݄30༵
まとめ22126݄30༵
まとめ• オブジェクトを責務とコラボレーションの視点から実装していくにはモックオブジェクトの力が必要である22126݄30༵
まとめ• オブジェクトを責務とコラボレーションの視点から実装していくにはモックオブジェクトの力が必要である• ドメインの複雑な問題に取り組むスキルとして、オブジェクト指向設計技術を少しでも学ぼう22126݄30༵
まとめ• オブジェクトを責務とコラボレーションの視点から実装していくにはモックオブジェクトの力が必要である• ドメインの複雑な問題に取り組むスキルとして、オブジェクト指向設計技術を少しでも学ぼう• 先人の知見の宝庫22126݄30༵
23ガイドとなる技術・書籍126݄30༵
オブジェクト指向設計• オブジェクトデザイン(レベッカ・ワーフスブラック/アラン・マクキーン)• ロール、責務、コラボレーション:責務駆動設計についての実践的な解説24126݄30༵
オブジェクト指向開発• Growing Object-Oriented Software,Guided byTests(SteveFreeman/Nat Pryce)• 通称「GOOS本」• 責務駆動設計とモックフレームワークをベースにテスト駆動開発する25126݄30༵
オブジェクト指向開発• アジャイルソフトウェア開発の奥義(ロバート・C・マーチン)ボブおじさん• アジャイル設計開発、オブジェクト指向設計の原則等26126݄30༵
27ありがとうございました!126݄30༵