PHP勉強会で「CIを半年間まわしてみて」というお題でLTをしてきました。昨年の11/30に、当時ちょうど開発が始まった案件の開発環境に関して「今時なCakePHPでの開発環境!?」というエントリーを書いて、初のホッテントリ入りしました。4月末でこのプトジェクトが始まって半年という事で、実際にCIをまわしている中で起こった事や、試行錯誤しつつどうやって解決したかなどを簡単にまとめてお話ししました。LT用に作った資料ではちょっと伝わりにくいので、以下にまとめ直しました。UnitTestのテストケースが467件、受入れテストのシナリオ数が292件とものすごい成長っぷりです。Plugin(BeHat)を使用しての受入れテストは書きましたが、TDD/BDDで開発していた訳ではありません。私自身もプロダクションのコードを書きながらテストコードを書いて、一通りブラウザ上で動作する所まで進んでから、受入れテストを書いていました。年末〜年始にかけて手伝ってくれるメンバーが3名増えたのですが、実際にコードを書き始めて起こったのが...プロダクションコードとテストコードが一緒にコミットされない!折角CIしているのにこれでは全く意味がありません。いう事で「テストコードが無いコードはmasterにマージしません!」と宣言して実際にマージしませんでした。masterにマージされなければ当然ステージング環境にも反映されませんので、ストーリ(チケット)が完了しません。いう事で(おそらく(^^;)渋々テストコードを書いてくれたんではないかと思います。自動テストに40分かかる開発も順調に進み、テストコードが増えてくると皆さん直面するスローテスト問題が発生しました。当初は、インスペクション(静的解析)/UnitTest/BDD(StoryTest)を順番に実行していたため、各処理を分割して、インスペクションとUnitTestは並列に実行する様にしました。ビルドパイプライン化してUnitTestが正常に完了した場合のみStoryTestを実行する様に変更しました。この変更ですべてが完了するのに20分台まで時間が短縮しました。今回のプロジェクトではビルドパイプラインを作って、masterブランチで受入れテストが正常に完了すると自動的にステージング環境にデプロイされる様になっています。Pluginを使って自動でマイグレーションしています。自動デプロイの際にこのマイグレーションに失敗してしまいました...。原因は単純なミスだったのですが、ステージング環境のDBがつじつまの合わない中途半端な状態になってしまいクライアントさんにごめんなさいして、再度構成し直しました。これがプロダクション環境で起きたら...と思うと冷や汗がでました。こんな問題が起こったかというと、Jenkins上のUnitTestやBDD環境でテストを実行する際のマイグレーション手順がステージング環境と違っていたためでした。この辺りにも書かれている通り、原則なはずの「すべての環境で、同じ手順でデプロイするべし」をしっかり守る事で、開発環境やテスト環境などで繰り返しデプロイ(この場合はマイグレーションですが...)が実行され、問題がある場合にも事前に発見出来る様になりました。selenium-standalone-serverが落ちるgithubのcommit時に自動でテストが実行されるので、CIサーバーはもちろん24時間動作しています。継続して運用をしていると、突然ストーリテストに失敗する様になってしまいました。原因を調査すると、selenium-standalone-serverが落ちていたり、メモリ不足が発生していました。メモリーリークが発生しているのだろうと予想して、ストーリテスト実行時に自動的にselenium-standalone-serverを再起動する様に設定したところ改善しました。ストーリーテストで時々エラーになる単独で実行したり、開発環境で実行すると問題なく動作するのにある特定のテストケースが時々エラーになるという謎現象が発生しました。調べた結果原因は簡単で、とあるモデルのアソシエーション先のorderが指定されていないため、環境/状況により並び順が変わってうことが原因でした。アソシエーション先のデータの並び順は通常の処理では問題にならない事もあるので、注意が必要かもしれません。スローテスト再び...ビルドパイプライン化して、30分を切っていたストーリーテストがまた40分程度かかる様になってしまいました。悩んだ結果、ストーリーテストを2つに分割して、同時に実行する様に修正しました。Plugin(BeHat)ではシナリオにタグを振る事ができるので、以下の様にJavaScriptを使っていてSeleniumServerを利用するシナリオと、それ以外のシナリオに分割しました。実際にタグで実行するストーリーを切り替えるには以下の様に実行します。javascriptタグが付いていないもの複数のタグを付ける事も出来るので、機能毎にタグを付けておくとテストの実行範囲を絞り込むことが出来てとても便利です。この修正で、実行時間はほぼ半分の20分程度まで改善しました。UnitTestがセグフォ通常のUnitTestを実行する分には、全件テストを実行しても256M程度割り当てていれば問題ないのですが、CodeCoverageを取得しようとすると、膨大なメモリが必要で、プロジェクト開始から半年経過した4月にはとうとう2G割り当ててもセグフォで落ちる様になってしまいました。CI用サーバーのメモリは4Gと立ち上げ当初は多めのものを用意したつもりだったのですが、厳しくなってきました。試行錯誤した結果、全件一括のテストを諦めてControllerのテストとそれ以外のテストの2つに分割して順番に実行する様にしました。カバレッジ自体は、Jenkinsが複数の結果をまとめてくれるのですが、詳細なhtmlレポートは今のところ統合出来ていません。不便なのでなんらか改善策を打ちたいなと思っています。テストケースが増えてくるとこの問題は必ず打ち当たる問題だと思います。皆さんがどんな風に解決しているかとても興味のあるところです!またしてもスローテスト...プロジェクトも終盤にはいって、JavaScriptをガンガン使う大きめの機能が複数完成したのに伴ってまたしてもストーリーテストの実行時間が30分を超えて、40分に迫りつつあります。これに関してはまだ対策は実施していません。4月末で、ひとまず開発作業にめどがつくので、時間を見つつテスト用のデータベースをインメモリ化してみようと思っています。4Gを使用しているのですが、UnitTestにしても、ストーリーテストにしても、Fixtureなどを利用してデータベースへの操作が多いテストを実行するとIO負荷が高くなりがちです。VPSにしてもIaaSにしてもHDDのアクセス性能はオンプレミスのサーバーに比べてかなりおそいので、ここがボトルネックになる事がありそうです。最近はSSDを使えるサービスなどもある様なので、色々と試してみたいと思います。まとめ今回クライアントさんの理解のおかげで、開発初期からCI環境を用意して進める事が出来、とても貴重な経験を出来ました。integration)は、日本語では継続的インテグレーションと訳されます。半年間継続してきて実感するのは、まさに継続していく事が肝だなと思いました。今後、このプロジェクトに限らずプロジェクトが進んでいく中で、色々と厳しい状況が発生する事があると思いますが、今回の取り組みを継続していきたいと思っています。月別アーカイブ著書はてなブログをはじめよう!kaz_29さんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。