frameworkテストの無いコードはレガシーコードだ!(挨拶こんにちは、フリューの九岡です。Testについて紹介します。Testって?「Playのフレームワーク本体と、アプリケーション全体(Model-View-Controller)を通したテスト」です。Playの公式ドキュメントでは以下のように説明されています。Testを利用すると、Controllerを直接叩く事でアプリケーションをテストできます。FunctionalTestを継承してテストスイートとします。実態は、JUnit4のテストケースにPlay独自のメソッドを追加したものになっています。FunctionalTestを継承してテストスイートとします。実態は、JUnit4のテストケースにPlay独自のメソッドを追加したものになっています。上記レスポンスに対する各種assertをしますassertIsOk(response);}}PlayのFunctionalTestでは、フレームワークとアプリケーションを通してテストするために、「HTTPリクエストをシミュレートして、レスポンスを検証」という方法を取ります。コード例では以下の部分です。OKを意味しています。HTTPリクエストをシミュレートするメソッドは、GETの他にPOST、DELETE、PUTも用意されています。レスポンスの検証についても、assertIsOkのようなステータスコードに対するものの他に、レスポンスヘッダやレスポンスボディを検証するメソッドが用意されています。その他、利用可能なメソッドについてはPlayのAPIリファレンスに記載されています。API)テストクラスの構成テストクラスは以下の2段構成で、普通のJUnitテストケースと同じです。略Beforeアノテーションをつけたメソッドは各テストメソッドの実行前、BeforeClassはテストクラスの実行前にそれぞれ実行されます。(この二つ以外にもJUnit4が提供しているアノテーションは利用できます。詳しくはJUnit4のドキュメントを参照してください。)通常、GET以外の操作はデータの追加・削除・更新など何らかの副作用を伴うはずです。そのような場合に、テストメソッドの実行順序でテスト結果が変わってしまうことのないように、BeforeやBeforeClassのタイミングで初期化を行うことをオススメします。ここでは、テストクラスの実行前にテスト中にずっと使い回す一時ファイルの作成を行っています。各テストメソッドの実行前には、JavaFixtures.deleteAll();1Fixtures.deleteAll();でデータベースの内容を全てクリアした後、JavaFixtures.load("data.yml");1Fixtures.load("data.yml");でdata.ymlの内容をDBにロード、さらに各テストケースの事前条件としてPhotoを1件作成してDBに保存しています。テスト時にはapplication.confでテスト用として指定したDBが利用されます。newでプロジェクトのひな形を生成したあと、特に変更していなければ、Shell%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=01%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0のようにインメモリーデータベースになっているはずです。Webサービスをつくるをネタに、いくつかテストメソッドを書いてみます。response);}上から順に、HTML・XML・JSONで/photosをリクエストしたときのレスポンスをテストしています。assertContentTypeでレスポンスのContent-Type、assertCharsetで文字コードが期待通りであることを検証しています。OK”であることを検証しています。レスポンスに応じたContent-Type、Charsetをセットするのは忘れがちなので注意したいところです。OK、Content-Typeがimage/pngで、かつ返却されたデータの長さが正しい事を検証しています。uploadedPhoto.dataUrl);}ファイルを実際にアップロードするリクエストを送信して、レスポンスが正しい事、またアップロードしたファイルの情報がDBに保存されていることを検証しています。レスポンス(JSON形式)の検証のため、Playに標準添付されているGson(Google製のJSONライブラリ)を利用しています。OKが返却されることを確認しています。OKが返却されることを確認しています。Testを書きました。Testでは、コントローラに対してGET/POST/PUT/DELETEなどのリクエストを送信して、ステータスコードやレスポンスボディなどが期待通りかを検証することでテストを行います。Testが一番だと思います。今回もソースコードはGitHubで公開していますので、参考にしてください。frameworkはじめまして。モバイル事業部の九岡です。昨年9月にフリューに転職してきて、社会人としては今年で4年目になります。JavaScriptとScala、そして御坂美琴(重要)をこよなく愛するWebエンジニアです。本ブログでは、私が個人的に気になっている技術(主にプログラミング言語やWebフレームワークになると思います)を「○○を作ってみた」という形でご紹介していきます。frameworkでRESTfulなWebサービスを作ってみました。frameworkは、2009年頃から開発が続けられている、個人的にイチオシのJava・Scala向けWebフレームワークです。Java」のような取り上げられ方をされて話題になったのですが、何故か流行らなかった不遇のWebフレームワークです。先日(2011/4/13)バージョン1.2がリリースされるなど、現在でも活発に開発が続いています。METHODで区別する」ような構造のWebサービスのことです。Wikipedia詳細な説明は、実装例とあわせてします。つくってみる今回は、簡易な「画像共有サービス」をつくってみました。巷の画像共有サービス(Flickrのようなもの)にはアカウント登録やコメント機能など色々なおまけがついていますが、ここでは画像をアップロードできる検索できる閲覧できる変更できる削除できるという5機能に絞ります。これをREST的に解釈して、今回は以下の2つのリソースがあるということにします。/photos/{id}/dataそして、これらのリソースに対する操作をそれぞれAPIとして切り出します。METHOD)」に割り当てて、今回は以下のように決めました。画像を削除するAPI一覧これを早速Playで実装してみます。ひな形の作成まず、playでアプリの雛形を作成します。どんなアプリを実装するときも、この方法で作成した雛形を少しずつ変更していけばOKです。fun!これでカレントディレクトリのrestというディレクトリ以下にアプリが作成されました。routes追加conf/routesに前述の5つのAPIのルート定義を書きます。コントローラのクラス名.メソッド名」になっています。指定したパスに、指定したメソッドでリクエストが来た場合、指定したコントローラのメソッドに処理を委譲する、という意味です。直感的ですね!コントローラの実装routesに記載したメソッドをコントローラに実装します。"\n");}error(buffer.toString());}}}レスポンスまわりのコードはPlay独特かもしれません。ポイントは以下の3つです。これ以外は見た目通りではないでしょうか。renderJSON(photos)で、Photoのリストをjsonにシリアライズしてレスポンスに出力します。APIが実装できます。render(photos)で、PhotoのリストをHTMLテンプレートに渡した上で描画します。renderの引数に渡したphotosは、HTMLテンプレートからもphotosという名前で参照できます。Photos.indexここでは、/photosのパスに拡張子なしjsonxmlの3パターンを許容しています。render()を読んだ場合、リクエストされたときの拡張子に応じて描画するテンプレートを規約により勝手に決めてくれます。Photos.indexの場合、拡張子を省略するとindex.html、.xmlならindex.xmlというテンプレートが使われます。FOUNDを返します。actionDefinition.url;}}ここでも詳細は割愛しますが、ポイントは以下の3点です。getter/setterが不要Javaに詳しい方は違和感を感じるかもしれません。Playのモデルではgetter/setterを書かなくてもOKです。etc)Playは標準でいくつかのインターセプターを用意しています。上記の例では、モデルをDBに永続化する前に必ず呼ばれるメソッドonSave()を実現するために使っています。value="Upload"/>#{/form}ここでの実装ポイントは4点です。タグ#{名前}#{/名前}でPlayに組み込まれているタグを呼び出せます。リンク@{コントローラ.メソッド(引数)}は、指定したコントローラのメソッドに対応するURLに置き換わります。変数の利用${変数}で、コントローラのrender()に渡した変数の値が参照できます。photo)のようなメソッドを定義したことを覚えていますか?POSTするときに、photo.title、photo.dataというパラメータを指定すると、それぞれphotoにセットされた状態でコントローラのメソッドに渡されます。as:'photo'}<photo><dataUrl>${photo.dataUrl}</dataUrl><data><UUID>${photo.data.UUID}</UUID><type>${photo.data.type}</type></data></photo>#{/list}</photos>前述の通り、/index.xmlをリクエストした場合はこのテンプレートが使われます。testで、Playに組み込みHTTPサーバが起動します。http://localhost:9000/photosにアクセスすると、Photos/index.htmlの内容が表示され、ページ内のフォームから画像のアップロードができます。本題のRESTfulなAPIを使ってみます。RESTfulなWebサービスの利点として、HTTP通信ができて、JSONやXMLをデコードできる言語・環境ならどこからでもアクセスできますが、ここではお手軽にjQueryでアクセスします。*/}});というようなコードになります。METHODとパスにより区別されます。/photos/{id}と定義したので、jQueryからリクエストするときのURLも’/photos/1’のようになります。}});という感じになります。frameworkを使うとお手軽にRESTfulなWebサービスが実装できることが、雰囲気だけでもわかっていただけたでしょうか?ソースコードはGitHubで公開しています。cloneしてみてください。次回は、このアプリのユニットテスト・ファンクションテストについて書きます。比較編クラウドみなさん、こんにちは!フリューでモバイルサイト開発を行っている鷲見といいます。とある案件が最終段階に差し掛かった2011年3月下旬、上司から「次の案件はソーシャルアプリです。開発完了までは1ヶ月。アクセス規模はかなり大きめです。はい、君はインフラ担当です。頑張って」(意訳)という非情な宣告を告げられました。「俺この案件が終わったらゆっくりと小説を読むんだ」なんて言ってたのは単なる死亡フラグでしかありませんでした。いいつつもこの短期間で物理サーバを見積り・調達して揃えるのはなかなか難しいので、フリューではまだ導入していなかった、クラウド環境の構築に乗り出してみることにしました。いうわけで、これから『クラウド1ヶ月導入記』と題して記事を掲載していこうと思います。ちなみに2011年4月11日現在このプロジェクトは進行中です!では、まずどのクラウド環境を導入するのか、上司を説得させるための材料を出すために各種クラウドを比較してみたいと思います。要件まずは今回必要な条件は以下の通りです。自動でスケールアウト・スケールインしてくれれば嬉しい価格が安ければ嬉しいクラウド比較クラウドと一概にいっても、IaaS,PaaS,SaaSといろいろあります。Service)ソフトウェアを必要な時に必要な分だけネット経由のサービスとして提供する今回は特定のソフトウェアを使うのではなく、作成したアプリケーションを公開したいので、IaaSかPaaSとなります。Azure,herokuなどが挙げられます。それでは上記要件と比較し、導入可否を検討してみます。herokuRubyしか使えないので今回は該当しません。AzureVisualStudioや.netframeworkに関する知識があまり無いので今回は見送ります。Codeに関する知識がほとんど無いので今回は見送ります。EngineJavaで開発は出来ますが、既存フレームワークが使えないため今回は見送ります。PaaSの候補は全滅してしまいました。いうわけでPaaSは諦め、IaaSという選択になります。Services,ニフティクラウド、さくらVPSなどが挙げられます。VPSはクラウドとは言いがたいのかもしれませんが、容易にインフラを準備できる環境ということで今回は比較対象としています。この3つのサービスは必須要件をすべて満たしうるので、スペックやサービスについて比較します。Xeon相当とIaaSでもいろいろ差があることがわかります。Servicesが優勢です。同じことが出来るのであれば次に大事なのはお金ということで、次回はこの3つのIaaSでクラウド環境を構築した場合の金額の見積りについて記載していきたいと思います。