Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.
「スピード」と「品質」を実現する 
PHP開発チームの取り組み 
! 
 ~AngularJS + FuelPHP + AspectMock~
何者? 
株式会社インテリジェンス 
 マーケティング企画統括部 
 サービス開発部 テクノロジーグループ 
! 
清田 馨一郎  
Twitter:@seikei1874 
【経歴】 
2002年 SIerに入社 
PGから叩き上げでPMまで...
何してる? 
サービス開発部 
 dots.(http://eventdots.jp/)の開発、運営 
 マーケティング部門の業務改善、見える化 
 … etc 
! 
(私の)ミッションを格好良く言うと 
 社内のデータサイロを見つけ、 
 ...
本日の内容
本日の内容 
【「スピード」と「品質」を実現する】取り組みを紹介 
その中でも、テストを中心に紹介 
PHP勉強会なので、AspectMockについて詳しく紹介 
Angularの技術的な話は。。。 
! 
ゴール 
 明日から、AspectM...
スピードと品質
スピードと品質 
計画(スプリント・プランニング) 
実装 
ユーザに見てもらう(スプリント・レビュー)
スピードと品質 
計画(スプリント・プランニング) 
サイクルを早く回す 
実装 
ユーザに見てもらう(スプリント・レビュー)
サイクルを早く回すために 
テストは極力自動化 
定常的、同じ作業は機械に任せる 
! 
細かいスパンでデプロイ 
ユーザは、見て・使ってみないと分からない 
頻繁なデプロイが負荷にならないために自動化 
! 
技術的負債は残さない 
開発者の...
開発
開発システム 
PHP :5.5系 
MySQL :5.6系 
FuelPHP :1.7.2 
 ※ 一部システムでは、Phalcon使ったり 
! 
Font-end :AngularJS、TypeScript 
Test :PHPUnit、...
開発フローとCI 
開発フロー 
 テストコードを書いて実装完了 
 Gitlabにマージリクエスト。レビューしてマージ 
 Jenkinsでテスト、デプロイ 
 Slackに通知して共有 
! 
CI 
 毎朝、実行 
 Slackに結果を通...
フロントサイド
FuelPHP 
FulePHPでは極力APIを作るようにする 
ビュー部分はAngularJSで作りこむ 
! 
素のController_Restでは、 
想定外エラーのレスポンスなど 
扱いヅライのでカスタマイズ
AngularJS 
多分に漏れず、DOM地獄から逃げたかった 
社内ツールではあるが、UIは今風にしたい 
! 
秘伝のjQueryソースは無くしたい 
ある程度、書き方が統一できる
TypeScript 
コンパイルを通すので、構文チェックができる。 
デバッグでエラー箇所が特定し易い 
→ 作業効率は上がる
Wijmo(ウィジモ) 
リッチUIを提供するJavaScriptライブラリ 
データグリッドやチャートなどのWidgetを多数提供 
AngularのDirectiveが標準で提供 
!
Grunt + Karma + Jasmine + PhantomJS 
Grunt 
 TypeScriptのコンパイル  
 Karmaの実行 
! 
 デプロイ、CI 
  JenkinsでGrunt実行 
! 
Jasmine 
API...
AspectMock
AspectMock 
モック フレームワーク 
https://github.com/Codeception/AspectMock 
! 
PHPテストフレームワーク「Codeception」と同じ作者 
! 
PHPでAOPを実現する「Go...
なぜAspectMock? 
テストフルなコード??? 
! 
FuelPHPとの親和性 
Fuelは、staticを多様 
1.7.2から標準で設定済(core/bootstrap_phpunit.php) 
! 
単体テストのバリエーション...
設定、使い方 
達人出版会 
「はじめてのフレームワークとし 
てのFuelPHP第2版(3) 実践編」 
! 
※AspectMock使用時のクラスロードエラーの解消の部分だけでも、1000円の価値はありました。 
○ PHP Advent ...
Proxy 
ClassProxy 
静的メソッドのMock 
! 
InstansProxy 
インスタンスのMock 
! 
Test Doubles Builder 
ClassProxy, InstansProxyを良しなに作成してくれ...
こんなときどうする? 
1. オブジェクトの中で呼んでいるstaticメソッド 
2. DBエラー、ネットワークエラーなどの例外 
3. 外部リソースからの取得データ 
4. 状態によって戻り値が変わるメソッド 
DEMOしながら説明します
まとめ 
• 定常、定期的な作業は積極的に自動化すべし 
• テストコードは、テスト実施と同時に書く 
• AspectMockを使えば、出来ないテストは無い(多分) 
• SpecメソッドでBDDも可能(試してません) 
• AspectMo...
ご質問ありますか? 
http://eventdots.jp/
ありがとうございました! 
http://eventdots.jp/ 
いっしょに働く仲間を募集中!!!
付録
FuelPHP 
想定外のエラー発生時も、ちゃんとレスポンスを返すようにする 
! 
 protected function response($data = array(), $message = '') {! 
! if(!array_ke...
AspectMockを使ってみる 
こんなクラスをMock化してみる 
<?php! 
! 
namespace Sample;! 
! 
class Model_User extends Model {! 
! 
private $_id;!...
AspectMockを使ってみる1 
<?php! 
use AspectMockTest as mock;! 
! 
class Test_Sample extends FuelCoreTestCase {! 
! 
protected fu...
AspectMockを使ってみる2 
/**! 
* @expectedException FuelException! 
*/! 
public function test_例外発生ケース() {! 
例外を強制的に発生できる 
DBエラー、...
AspectMockを使ってみる3 
public function test_Privateなメソッドのケース() {! 
privateメソッドもMock化できる 
 ※AspectMockの機能ではありませんが、Closureでpriva...
AspectMockを使ってみる4 
<?php! 
namespace Sample;! 
! 
use FuelCoreDB;! 
! 
class Model_Transaction extends Model {! 
! 
public...
AspectMockを使ってみる4 
public function test_呼び出し回数で挙動を変えるケース() ! 
{! 
! $cnt = 0;! 
! $mock = mock::double(! 
'FuelCoreDB',! 
...
AspectMockを使ってみる5 
【ケース】 
ORMでfindした値が、 
想定どおりの処理が行われた値で 
saveされるかを確認したい 
<?php! 
! 
namespace Sample;! 
! 
class Model_Or...
AspectMockを使ってみる5 
確認したいORMクラ 
スを継承してfindし 
た結果をダミー値で 
定義。 
! 
saveの引数を無名関 
数でチェック 
<?php! 
Autoloader::add_namespace(‘Sam...
Prochain SlideShare
Chargement dans…5
×

「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~

8 096 vues

Publié le

2014年12月09日にヒカ☆ラボに登壇された株式会社インテリジェンスの清田氏のスライド資料です。

Publié dans : Ingénierie
  • If you want to download or read this book, copy link or url below in the New tab ......................................................................................................................... DOWNLOAD FULL PDF EBOOK here { http://bit.ly/2m6jJ5M } .........................................................................................................................
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • accessibility Books Library allowing access to top content, including thousands of title from favorite author, plus the ability to read or download a huge selection of books for your pc or smartphone within minutes DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { http://bit.ly/2m6jJ5M } ......................................................................................................................... Download Full EPUB Ebook here { http://bit.ly/2m6jJ5M } ......................................................................................................................... ...................................ALL FOR EBOOKS................................................. Cookbooks, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy,
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • If you want to download or read this book, copy link or url below in the New tab ......................................................................................................................... DOWNLOAD FULL PDF EBOOK here { http://bit.ly/2m6jJ5M } ......................................................................................................................... Download EPUB Ebook here { http://bit.ly/2m6jJ5M } .........................................................................................................................
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • If you want to download or read this book, copy link or url below in the New tab ......................................................................................................................... DOWNLOAD FULL PDF EBOOK here { http://bit.ly/2m6jJ5M } ......................................................................................................................... Download EPUB Ebook here { http://bit.ly/2m6jJ5M } .........................................................................................................................
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT (Unlimited) ......................................................................................................................... ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download Full EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ACCESS WEBSITE for All Ebooks ......................................................................................................................... Download Full PDF EBOOK here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download EPUB Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... Download doc Ebook here { https://tinyurl.com/yyxo9sk7 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici

「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~

  1. 1. 「スピード」と「品質」を実現する PHP開発チームの取り組み !  ~AngularJS + FuelPHP + AspectMock~
  2. 2. 何者? 株式会社インテリジェンス  マーケティング企画統括部  サービス開発部 テクノロジーグループ ! 清田 馨一郎  Twitter:@seikei1874 【経歴】 2002年 SIerに入社 PGから叩き上げでPMまで経験 大手企業の基幹システムからソーシャルゲーム開発まで幅広く経験   2014年04月から、インテリジェンスへJOIN 石抱き
  3. 3. 何してる? サービス開発部  dots.(http://eventdots.jp/)の開発、運営  マーケティング部門の業務改善、見える化  … etc ! (私の)ミッションを格好良く言うと  社内のデータサイロを見つけ、  サイロをつなぐデータパイプラインを構築し、  ビジネスの加速を促す
  4. 4. 本日の内容
  5. 5. 本日の内容 【「スピード」と「品質」を実現する】取り組みを紹介 その中でも、テストを中心に紹介 PHP勉強会なので、AspectMockについて詳しく紹介 Angularの技術的な話は。。。 ! ゴール  明日から、AspectMockが使いたくなっちゃう♥
  6. 6. スピードと品質
  7. 7. スピードと品質 計画(スプリント・プランニング) 実装 ユーザに見てもらう(スプリント・レビュー)
  8. 8. スピードと品質 計画(スプリント・プランニング) サイクルを早く回す 実装 ユーザに見てもらう(スプリント・レビュー)
  9. 9. サイクルを早く回すために テストは極力自動化 定常的、同じ作業は機械に任せる ! 細かいスパンでデプロイ ユーザは、見て・使ってみないと分からない 頻繁なデプロイが負荷にならないために自動化 ! 技術的負債は残さない 開発者の精神的安定
  10. 10. 開発
  11. 11. 開発システム PHP :5.5系 MySQL :5.6系 FuelPHP :1.7.2  ※ 一部システムでは、Phalcon使ったり ! Font-end :AngularJS、TypeScript Test :PHPUnit、AspectMock、Karma、Jasmine、PhantomJS コミュニケーション :Slack ジョブ管理 :SOS JobScheduler ビルド、デプロイ :Grunt、Fabric CI :Jenkins 構成管理 :Gitlab 開発環境 :Vagrant 課題管理 :OpenProject
  12. 12. 開発フローとCI 開発フロー  テストコードを書いて実装完了  Gitlabにマージリクエスト。レビューしてマージ  Jenkinsでテスト、デプロイ  Slackに通知して共有 ! CI  毎朝、実行  Slackに結果を通知
  13. 13. フロントサイド
  14. 14. FuelPHP FulePHPでは極力APIを作るようにする ビュー部分はAngularJSで作りこむ ! 素のController_Restでは、 想定外エラーのレスポンスなど 扱いヅライのでカスタマイズ
  15. 15. AngularJS 多分に漏れず、DOM地獄から逃げたかった 社内ツールではあるが、UIは今風にしたい ! 秘伝のjQueryソースは無くしたい ある程度、書き方が統一できる
  16. 16. TypeScript コンパイルを通すので、構文チェックができる。 デバッグでエラー箇所が特定し易い → 作業効率は上がる
  17. 17. Wijmo(ウィジモ) リッチUIを提供するJavaScriptライブラリ データグリッドやチャートなどのWidgetを多数提供 AngularのDirectiveが標準で提供 !
  18. 18. Grunt + Karma + Jasmine + PhantomJS Grunt  TypeScriptのコンパイル   Karmaの実行 !  デプロイ、CI   JenkinsでGrunt実行 ! Jasmine APIレスポンスをスタブ化し、 テストが柔軟にできる
  19. 19. AspectMock
  20. 20. AspectMock モック フレームワーク https://github.com/Codeception/AspectMock ! PHPテストフレームワーク「Codeception」と同じ作者 ! PHPでAOPを実現する「Go-AOP」を使用して メソッドを差し替える仕組み ! Go-AOP https://github.com/lisachenko/go-aop-php AOP:アスペクト志向プログラミング
  21. 21. なぜAspectMock? テストフルなコード??? ! FuelPHPとの親和性 Fuelは、staticを多様 1.7.2から標準で設定済(core/bootstrap_phpunit.php) ! 単体テストのバリエーションが増える  テストデータ作成に苦労しない 異常ケースが容易にできる
  22. 22. 設定、使い方 達人出版会 「はじめてのフレームワークとし てのFuelPHP第2版(3) 実践編」 ! ※AspectMock使用時のクラスロードエラーの解消の部分だけでも、1000円の価値はありました。 ○ PHP Advent Calendar 2014 kenjisさんの記事 「普通じゃないモッキングフレームワークAspectMockがパワフル過ぎる」   http://blog.a-way-out.net/blog/2014/12/10/aspect-mock/
  23. 23. Proxy ClassProxy 静的メソッドのMock ! InstansProxy インスタンスのMock ! Test Doubles Builder ClassProxy, InstansProxyを良しなに作成してくれる ! FuncProxy (>= 5.0.0) 指定したNamespaceのファンクションをMock化。 NativeファンクションもMock化可能!!
  24. 24. こんなときどうする? 1. オブジェクトの中で呼んでいるstaticメソッド 2. DBエラー、ネットワークエラーなどの例外 3. 外部リソースからの取得データ 4. 状態によって戻り値が変わるメソッド DEMOしながら説明します
  25. 25. まとめ • 定常、定期的な作業は積極的に自動化すべし • テストコードは、テスト実施と同時に書く • AspectMockを使えば、出来ないテストは無い(多分) • SpecメソッドでBDDも可能(試してません) • AspectMockのクセは強いので慣れましょう
  26. 26. ご質問ありますか? http://eventdots.jp/
  27. 27. ありがとうございました! http://eventdots.jp/ いっしょに働く仲間を募集中!!!
  28. 28. 付録
  29. 29. FuelPHP 想定外のエラー発生時も、ちゃんとレスポンスを返すようにする !  protected function response($data = array(), $message = '') {! ! if(!array_key_exists('error_code', $data)) {! ! ! $m_array = Arr::merge(array('error_code' => '200', 'message' => $message), array('data' => $data));! ! }! ! parent::response($m_array);!  }! !  public function router($resource, $arguments) {! ! try {! $ret = parent::router($resource, $arguments);! ! if ($ret === false) {! parent::response(array('error_code' => '403', 'message' => 'Exception'), 403);! }! } catch (Exception $e) {! Log::error($e->getTraceAsString());! Log::error($e->getMessage());! ! parent::response(array('error_code' => '500', 'message' => 'Internal error.'), 500);! }! }!  }!
  30. 30. AspectMockを使ってみる こんなクラスをMock化してみる <?php! ! namespace Sample;! ! class Model_User extends Model {! ! private $_id;! private $_name;! ! public function __construct($id, $name) {! $this->_id = $id;! $this->_name = $name;! }! ! public function getName() {! return $this->_name;! }! ! public function getDate() {! return date('Y-m-d H:i:s');! }! } <?php! ! namespace Sample;! ! class Model_Suser extends Model {! ! private static $_name = '静的な値';! ! public static function getName() {! return static::$_name;! }! ! public static function callPrivate() {! return static::privatefunc();! }! ! private static function privatefunc() {! $time = FuelCoreDate::time();! return "private:" . $time . PHP_EOL;! }! }
  31. 31. AspectMockを使ってみる1 <?php! use AspectMockTest as mock;! ! class Test_Sample extends FuelCoreTestCase {! ! protected function setUp() {! Autoloader::add_namespace(! ! ! ! ‘Sample',! ! ! ! APPPATH . 'classes' . DS . 'sample/');! }! ! public function test_インスタンスProxyのケース() {! $user = new SampleModel_User(1, 'TestName');! ! // Mock化! $mock = mock::double($user,! ! ! ! ['getName' => 'DummyName']);! ! // 指定したNamespace内であれば、標準関数もMock化できる! mock::func('Sample', 'date', ‘now!!');! ! $name = $user->getName();! $data = $user->getDate();! ! $mock->verifyInvokedOnce('getName');! $mock->verifyInvokedOnce('getDate');! ! $this->assertEquals('DummyName', $name);! $this->assertEquals('now!!', $data);! }! } public function test_ClassProxyのケース() ! {! ! mock::double('SampleModel_Suser', [! ! ! ! ! ! 'getName' => 'Dummy']);! ! $name = SampleModel_Suser::getName();! ! $this->assertEquals('Dummy', $name);! ! } インスタンスもMock化 クラス名からMock化 標準関数もMock化!
  32. 32. AspectMockを使ってみる2 /**! * @expectedException FuelException! */! public function test_例外発生ケース() {! 例外を強制的に発生できる DBエラー、ネットワークエラーなど、発生させ難いテストが容易になる ! mock::double('SampleModel_Suser', [! 'getName' => function() {throw new FuelCoreFuelException("例外発生");}! ]);! ! try {! SampleModel_Suser::getName();! ! } catch (FuelException $e) {! ! $this->assertTrue(true);! throw $e;! }! ! $this->assertTrue(false);! }!
  33. 33. AspectMockを使ってみる3 public function test_Privateなメソッドのケース() {! privateメソッドもMock化できる  ※AspectMockの機能ではありませんが、Closureでprivateメソッドが直接呼べる ! // privateメソッドで呼んでるクラスをMock化! mock::double('FuelCoreDate', ['time' => 'hogehoge']);! ! // Privateメソッドを直接呼ぶ! Closure::bind(! function () {! $obj = new SampleModel_Suser();! $ret = $obj->privatefunc();! ! $this->assertEquals('private:hogehoge' . PHP_EOL, $ret);! },! $this,! 'SampleModel_Suser'! )->__invoke();! ! mock::clean();! mock::double('SampleModel_Suser', ['privatefunc' => 'プライベート関数もMock化']);! ! $ret = SampleModel_Suser::callPrivate();! $this->assertEquals('プライベート関数もMock化', $ret);! ! }
  34. 34. AspectMockを使ってみる4 <?php! namespace Sample;! ! use FuelCoreDB;! ! class Model_Transaction extends Model {! ! public static function transaction() {! ! if(!DB::in_transaction()) {! DB::start_transaction();! }! ! try {! // DB処理! Model_Orm_User::find();! ! DB::commit_transaction();! ! } catch(FuelException $e) {! if(DB::in_transaction()) {! DB::rollback_transaction();! }! ! throw $e;! }! }! }! 【ケース】  例外が発生したときの挙動をテストしたい    1. トランザクションが無ければ貼る  2. 例外が発生しとき、トランザクションが    貼ってあれば、Rollbackする
  35. 35. AspectMockを使ってみる4 public function test_呼び出し回数で挙動を変えるケース() ! {! ! $cnt = 0;! ! $mock = mock::double(! 'FuelCoreDB',! [! 'start_transaction' => true,! 'commit_transaction' => true,! 'rollback_transaction' => true,! 'in_transaction' => function () use (&$cnt) {! if ($cnt == 0) {! $cnt++;! return false;! } elseif ($cnt == 1) {! $cnt++;! return true;! } else {! $cnt++;! return __AM_CONTINUE__; // オリジナルの処理がされる! }! }]);! ! mock::double('SampleModel_Orm_User', [! ! ! ! 'find' => function() {! ! ! ! ! throw new FuelException(“Exception強制発生");}! ! ! ]);! ! try {! SampleModel_Transaction::transaction();! } catch(FuelException $e) {! $mock->verifyInvokedOnce('start_transaction');! $mock->verifyNeverInvoked('commit_transaction');! $mock->verifyInvokedMultipleTimes('in_transaction', 2);! $mock->verifyInvokedOnce('rollback_transaction');! }! } 無名関数の引数に 変数を参照渡しして 呼び出し回数を カウント
  36. 36. AspectMockを使ってみる5 【ケース】 ORMでfindした値が、 想定どおりの処理が行われた値で saveされるかを確認したい <?php! ! namespace Sample;! ! class Model_Orm_User extends OrmModel! {! ! <?php! ! namespace Sample;! ! class Model_Update extends Model! {! public static function update()! {! $model = Model_Orm_User::find();! ! foreach($model as $ret) {! $ret['val'] = 'hugehuge';! $ret->save();! }! }! }! protected static $_properties = [! 'id',! 'val',! ];! }!
  37. 37. AspectMockを使ってみる5 確認したいORMクラ スを継承してfindし た結果をダミー値で 定義。 ! saveの引数を無名関 数でチェック <?php! Autoloader::add_namespace(‘Sample',! ! ! ! ! APPPATH . 'classes' . DS . 'sample/');! ! class Tests_Model_StubModel extends SampleModel_Orm_User {! ! protected $_data = [‘id','val'];! ! function __construct($id, $val){! $this->_data['id'] = $id;! $this->_data['val'] = $val;! }! } public function test_ORMでの更新値チェックのケース() {! // ORMでDBから値を取得して処理して更新するパターン! $modify_data = 'hugehuge';! ! $data = new Tests_Model_StubModel('1', 'hogehoge');! ! mock::double('SampleModel_Orm_User',! [! 'find' => function ($param) use ($data) {! // ORMのfindは、レコード単位のORMクラス配列が返る! return [$data];! }! ]);! ! mock::double('OrmModel',[! 'save' => function() use ($modify_data) {! FuelCoreTestCase::assertEquals(! ! ! ! $this->_data['val'], $modify_data! ! ! );! }! ]);! ! SampleModel_Update::update();! }!

×