vol.1

Magazine

Japan Grails/Groovy User GroupG* Magazine 創刊のごあいさつ
日本 Grails/Groovy ユーザーグループ (Japan Grails/Groovy User Group = JGGUG) は、2009 年 2 月。デベロッパ・サミットへの参加に合わせて発足しました。
その前身は 2007 年 7 月 25 日に始まった Grails コード・リーディングであり、2006 年 8 月からおもに
Grails のドキュメント翻訳を目的に立ち上がった grails-ja (Google Groups) です。Grails はまだバージョン
1.0 にも満たない、いわば胎児ともいえる時期でした。現在 JGGUG には 200 名を超えるメンバが参加し、首都圏、関西、名古屋を拠点として、ほぼ毎月ワークショップを開催、2011 年 2 月からは電子雑誌として G* Magazine を創刊します。
Groovy を中心として、Grails、Griffon、Gaelyk、Gradle などは、Java を補完する強力な G* エコ・シス
テムを構築しつつあります。これからのソフトウェア開発に欠かせない G* を学び、使いこなすために
JGGUG への参加をお待ちしています。 http://www.jggug.org/ をご覧下さい。
日本 Grails/Groovy ユーザーグループ
代表

山田 正樹

Contents
Series 01

Grails をコントロールせよ ! Part1………… 4
Series 02

Griffon 不定期便

〜第 2 回 バインディング編〜… ……………………… 10
Series 03

CodeNarc を利用して GROOVY のコード品質を上げる〜第 1 回 CodeNarc とは〜……………………………… 16
Series 04

Geb ではじめる Web テスト〜第 1 回 導入編〜… …………………………………… 19
Series 05

Grails Plugin 探訪〜第 2 回 Spock プラグイン〜… ……………………… 24
Information

リリース情報……………………………………… 28
JGGUG ４コマ漫画「ぐるーびーたん」………………… 29

G*Magazine vol.1

Grailsをコントロールせよ! Part 1
山本
series01

剛（株式会社ニューキャスト）

出版・印刷関連のシステム設計開発等に従事するテクニカル DTP アーキテクト。
日本 Grails/Groovy ユーザーグループ名古屋支部長。2006 年より Grails のドキュメント翻訳、
その後、Grails 公式の Acegi プラグインを開発。書籍『Grails 徹底入門』( 翔泳社発行 ) の 9、10、11 章を執筆。

本稿から 2 回に分けて、「Grails をコントロールせよ！」と題しれ、必ずクラス名の最後が Controller で終わる必要があります。

プリケーションの UI 設計との連携に必要な URL の定義方法など

は、クラス名の最後が Controller にするのを忘れないようにしまて、コントローラからプレゼンテーション層の連携と、Web アを解説します。先ずは、どのように要求を受けてどのように結果を返すか、そこでどのような受け返しができるか、その内容を内

生成コマンドを使わないでコントローラクラスを追加するとき
しょう！

では生成されたコントローラクラスの内容を見ていきます。単外共に解りやすく定義できるかを理解することで、Grails をきれ

純な groovy のクラスとして生成され、コードとしては index とコントローラを記述する場所 " アクション " と呼びます。アクションはコント

いにコントロールできるようになれると良いでしょう。

コントローラは、クライアントからのリクエストを受け取り、リクエストの内容に応じて処理を行い、ビューを返すクラスです。

いうクロージャがあらかじめ記述されています。これを処理単位
ローラクラス内に複数記述することが可能です。

このアクションにドメインモデル操作などの処理を記述して、アクションからビューにモデルを渡す、またはアクションから、（※ここでは MVC2 の細かな話は割愛させていただきます。）アプ

そのまま文字列を返す等の処理を記述できます。

部分になります、と、簡単に言うと怒られるかもしれませんが、レクト処理、他にも様々なコントローラ・アクション内で使用でGrails でコントローラクラスを作成するには、create-controller

されています。これは、Grails で初めて開発する人には不思議なリケーションのリクエスト・処理などの動作をコントロールする

コントローラクラスには、ビューテンプレート指定や、リダイ

初心者の方はその解釈で充分だと思います。

きるメソッドや、request,response,sesson 等の変数が動的に追加コマンドを実行することで、コントローラのスケルトンを生成し状態に見えます。そして何が活用できるかは、実際にドキュメンてくれます。

■Grails でのコントローラの基本

まずはじめにコントローラクラスを生成します。プロジェクトの階層で以下のコマンドを実行して Home コントローラを作成。

※ Grails での開発経験がある方はここは読み飛ばしてもかまいません。

grails create-controller home

# クラス生成時にパッケージを指定する事もできます。
grails create-controller jp.company.Home
grails-app/controllers 階層のパッケージ階層以下にコントロー

ト無しには解りにくくなっているのも Grails の特徴 !? の一つとなります。（公式ドキュメント http://grails.org/doc/latest）

解りにくいと言い切ってしまうのも・・・なので、最低限のコ

ントローラクラスの説明は終わりとして、ここから実際に動作できるコードでしていきます。

■ 簡単に動作させてみよう

最初に ( ※よく質問受けるので ) 前提としてコントローラは、プ
ロトタイプです。リクエスト毎にコントローラは生成されます。
コントローラからビューの連携には様々な方法があります。まずは、簡単なハローワールドを記述して動かしてみましょう。
class HomeController {ラクラスが生成されます。同時にビュー用の gsp を配置するため

def index = {の階層 grails-app/views/home が作成されます。今回のコマンド

render 'Hello World!'

で生成されたコントローラクラスの内容は、次のような内容になります。

▼HomeController.groovy
package gmag01}}
render 'Hello World!' と記述して起動します（grails run-app）、

そして、http://localhost:8080/gmag01/home/index にアクセス

class HomeController {します。この例では、単純に 'Hello World!' と文字列を返しブラ}

ポンス処理から、ビューへの連携等、多彩に幅広く活用できるメ

この例では、生成時にパッケージを指定していないため、アプWorld!' の部分を、次のように、text: と指定して記述することも

def index = { } // アクション

リケーション名がパッケージ名として自動的に付加されています。
（grails-app/controllers/gmag01/HomeController.groovy）

コントローラクラスは、grails-app/controllers 階層内に配置さウザー画面に表示します。この "render" は単純なテキストのレス
ソッドです。またこの例では、省略していますが、render 'Hello
できます。

render text:'Hello World!'

Grails をコントロールせよ！ Part 1

4

G*Magazine vol.1▼index.gsp<html><head><title>index ページ </title><meta name="layout" content="main" /></head><body>
username: ${username} score is ${score}

ハローワールド画面</body>次のサンプルはリクエストクエリー付きになります。

</html>class HomeController {ビュー用の GSP ファイルを指定することもできます。次の例でdef index = {は "grails-app/views/home/foo.gsp" を指定しています。

render "Hello ${params.who}!"class HomeController {}def index = {}render view:"foo", model:

render 'Hello World!' を "Hello $\{params.who\}!" に 変 更 し て[username:"tyama",score:2500]

みます。そして、先ほどの URL の後ろに ?who=World を追加した http://localhost:8080/gmag01/home/index?who=Worldにアクセスします。今回は、params 変数をプロパティ参照した、
params.who をレスポンス結果を返すコードに追加しました。リ

クエストクエリーのパラメータは、コントローラの機能で自動的}}
ここまでの内容で、簡単にリクエストを行いパラメータを取得してアクションで処理を行いレスポンスするという一連の動作はに収集され、params（詳細は後述）変数に収納されます。パラメー

わかったと思います。

"." に次いでパラメータキーを指定するだけです。

した URL をみると、"/gmag01/home/index" これを置き換えて説タを参照するには、params.who のように、params 変数に対して、

では、次に簡単に GSP と連携をしてみましょう。GSP は、何も定義しない場合、"grails-app/views/ コントローラ名 / アクション

名 .gsp" ファイルに関連づけられます。例えば次のコード例では、

そして、もう気付いてると思いますが、ブラウザーでアクセス

明すると、"/ アプリケーション名 / コントローラ名 / アクション名" となっていることがわかります。これは Grails での URL の基本となります。URL マッピング（詳細は次号）を定義して変更する事も可能です。

アクションに特に何も指定しないと自動的に、"grails-app/views/

home/index.gsp" を GSP としてビューを表示します。そして該当ファイルが無い場合は、次に "grails-app/views/home/index.jsp"

ファイルを探しにいき、JSP ファイルも存在しなければ、エラー
コード 404 を返す流れとなります。
class HomeController {def index = {//}}前の例では返値を何も返してません。アクションの最後に返値の Map を返すことで GSP へモデルを渡すことができます。
class HomeController {def index = {[username:"tyama",score:2500]}

URL とコントローラの関係■render、redirect、chain、forward

簡単にコントローラを動作させることができたところで、アクションからのコントロールをするために大事な、ここまでに一部例としても出てきた render、redirect、chain、forward という４つのメソッドを紹介します。ほとんどがそれぞれ読んで字のごと}くですが、多彩な機能を持つ render をはじめ、それぞれ使い方

GSP でのモデルの参照は、このようになります。

これらを上手く活用することで Grails のリクエスト処理を快適にがシンプルのようで、それなりに複雑さも持ち合わせています。
コントロールできます。

Grails をコントロールせよ！ Part 1

5

G*Magazine vol.1●render

render は様々なビューレスポンスを返すためのメソッドです。

ト内では "it" で参照できます。

render を使用して単純なテキスト、ビューやテンプレートの指

render template:"list",collection:[1,2,3,4],

コード等、多彩にレンダリング操作を行えます。

マークアップビルダーを使用する。

定、XML、JSON、マークアップを使った XML のレスポンス、エラー
単純なテキストレスポンス例。
render "Hello!"// 又はvar:"num"

def users = ['user1','user2']
render(contentType:"text/xml") {followers {render text:"Hello!"

users.each{user->{code}

username(user)

コンテントタイプ・エンコーディングも指定できる。

}{code}

render text:"<message> こんにちわ </message>",
contentType:"text/xml", encoding:"UTF-8"
ビューを指定する例。前述しましたが、view にビューファイ

ル名、model に返すモデルを指定します。
render view:"foo", model:[username:"tyama",score:2500]}}
例では若干中身を変えないと動きませんが、JSON の場合は、単純にコンテントタイプを "text/json" に変更。
def users = ['user1','user2']
render(contentType:"text/json") {followers:users// 上記の例では、アクションを記述したコントローラ用の}// 別の階層を参照するには、パスで指定します。(.gsp は

次回の REST でも紹介しますが、JSON・XML を返す場合は、コビュー階層を参照します。
省略 )render view:"/common/foo", model:[username:"tyama",score:2500]

ンバーターを使用できます。

コンバーターを import します。

// プラグイン内にあるビューを指定するには。

import grails.converters.*

render plugin:"myplugin", view:"foo", model:

そして render では、それぞれ次のように記述します。

[username:"tyama",score:2500]※コード例中に説明があるように、ビューファイルの指定は、
grails-app/views をルートとして、拡張子なしの絶対パスで指定します。

テンプレートを指定する例。テンプレート用ビューファイルは、

ファイル名の先頭に "_" を付加します。（例）_mytemplate.gsp
render template:"mytemplate", model:[username:"tyama",score:2500]
テンプレートにビーンを指定してビューに渡す。
render template:"list",bean:new
Person(name:'tyama', age:27)//gsp の内容

<user>${it.name} (${it.age})</user>
テンプレートでコレクションを扱う。テンプレート _list.gsp を指定して、コレクション [1,2,3,4] を表示させます。
▼_list.gsp<item>${num}</item>

render Book.list(params) as JSON
render Book.get(params.id) as XML
HTTP のステータスを返す事もできます。
render status: 503, text: 'Failed..'
以上が render の使用方法になります。レンダリングの指定方

法が多数有りますが、AJAX を使用したり、ポータル的にパーツを返したり等の用途によって、使いやすい方法を選択して活用しましょう。
●redirect

リダイレクトを行うメソッドです。リクエストを受けたアクションから、指定した場所へ HTTP のリダイレクトを行います。

コントローラ・アクション・ID を指定すると、内容に従って

URI を形成した対象へリダイレクトします。次の例では、"/user/
show/1" へリダイレクトされます。

redirect controller:"user", action:"show", id:1
このサンプルに params を指定する事もできます。次の例では、"/user/show/1?status=good" へリダイレクトされます。

collection にコレクションを指定して、テンプレートで参照する

変数を var に指定します。var が省略された場合は、テンプレー
Grails をコントロールせよ！ Part 1

6

G*Magazine vol.1

redirect controller:"user", action:"show", id:1,
params:[status:'good']
フラグメント指定。先ほどの例に "/user/show/1#comment" のように "#comment" と最後に追加します。

redirect controller:"user", action:"show", id:1,
fragment:"comment"●actionName、controllerName

先ずはじめに簡単な物から紹介。意外と使わないようでお世話になる変数、actionName、controllerName。これももちろん読んで字のごとく、それぞれ参照した場所のアクション名、コント
ローラ名を取得できます。

render " コントローラ名は ${controllerName} でアクション名は ${actionName} です。"

通常の URL、URI の指定も可能です。

●session

redirect uri:"/user/list"の 実 装 で あ る org.codehaus.groovy.grails.web.servlet.mvc.

redirect url:"http://www.yahoo.co.jp"

GrailsHttpSession が参照できます。HttpSession のメソッド実行のほか、セッション内容に対して Groovy マップのようにアクセ●forward

HTTP リダイレクトとは違いサーバサイド側でフォワードするメソッドです。redirect とほとんど同じですが、forward では、コントローラ・アクション・ID・パラーメータのみの扱いになります。

forward controller:"user", action:"show", id:1,
params:[status:'good']

スすることができます。

def username = session["username"]session.username●request

request は、HttpServletRequest の イ ン ス タ ン ス で す。

HttpServletRequest の 実 装 で あ る org.apache.catalina.core.
ApplicationHttpRequest が参照できます。HttpServletRequest に●chain

別のアクションへ HTTP リダイレクトを行いながら、アクションを連携する場合に使用するメソッドです。
公式ドキュメントから例を拝借。
class HomeController {def first = {chain(action:second,model:[one:1])}
def second= {println chainModel.one
chain(action:third,model:[two:2])}
def third = {[three:3]}}
この例で /home/first にアクセスすると、最終的に /home/thirdに到達して、アクション third から返るモデルは、[one:1, two:2,

three:3] になります。chain で渡されたモデルは、"chainModel"から参照できます。

■コントローラの変数

コントローラには、さまざまなプロパティが動的に設定されています。「簡単に動かしてみよう」で試したように、リクエス
トのパラメータを参照するための params をはじめとして、Grails

は Java のフレームワークなので、もちろん、session、request、
response、servletContext も参照可能です。他に次のリクエストまで内容を保持するテンポラリ収納用マップの変数 flash 等があります。

session は、HttpSession の イ ン ス タ ン ス で す。HttpSession

ある通常の機能に加えて、Grails では便利なメソッド・フィールドが追加されています。

※（注意）機能によっては開発時に使う必要は無く、内部的に利用するための機能でもあるので、乱用注意！

REST で活用できる機能。それぞれ XML、JSON を受け取った場

合に以下のように参照できます。

def xml = request.XML // XmlSlurper の GPathResult
def json = request.JSON // Grails の JSONObject
リクエストが get または post かを判別する。
if(request.get){//get の場合

}else if(request.post){//post の場合}
HttpServletRequest の getAttribute も簡単にアクセスできるよ

うになっています。アトリビュートの参照は、例のように簡単にアクセスできるほか、request に対して、each、find、findAll も使用できます。

def username = request['username']def score = request.score
フォーム送信時に <form> に enctype="multipart/form-data" が存在した場合、言い換えるとマルチパートデータのフォーム送信時は、自動的に、MultipartHttpServletRequest になります。ファイルアップロードを行う場合は、request.getFile() として、次のコード例のように取得できます。request.getFile() で取得したイ
Grails をコントロールせよ！ Part 1

7

G*Magazine vol.1
ン ス タ ン ス は Spring の MultipartFile（org.springframework.web.
multipart.MultipartFile）です。

def uploadFile = request.getFile('upload')
uploadFile.transferTo( new File('/dir/to/save/file.jpg') )println params.username
def user = User.get(params.id)
params は、ただ単にリクエストパラメータを収納して参照するだけではなく、コントローラの開発を柔軟でスムーズに進めるための機能を多く持っています。その説明は次の「リクエストパ●response

ラメータ型変換、バインディング、コマンドオブジェクト」で細HttpServletResponse の 実 装 で あ る org.codehaus.groovy.grails.

■リクエストパラメータ型変換、バインディング、コマ
ンドオブジェクト

response は、HttpServletResponse の イ ン ス タ ン ス で す。

web.sitemesh.GrailsContentBufferingResponse が参照できます。
def downloadFile = {byte[] bytes = // バイト配列
response.outputStream << bytes}

かく説明していきます。

Grails では、リクエストパラメータをドメインクラス・モデルと簡単にバインドできる仕組みが提供されています。バインディ
ングの説明をするには、ドメインクラスが関係してきますが、今回はドメインクラスの深い内容は割愛します。
●型変換●servletContext

servletContext は、ServletContext の イ ン ス タ ン ス です。ServletContext の 実 装 で あ る org.apache.catalina.core.
ApplicationContextFacade が参照できます。

servletContext も他のと同様に、getAttribute が簡単にアクセスできるようになっています。

def setting = servletContext["setting"]
servletContext["setting"] = "hoge"params にはリクエストで受けた内容を正確に受け取るために便利な型変換機能が備えられています。

例えば、次のようなコードがあるとします。

def num = params.num
if(num){println num+10}
この例では、params.num に文字列がセットされていた場合は、正常な処理結果が得られません。これを解決するのに params 型●flashflash は、次のリクエストまで使用できる一時保存マップです。

次のリクエストが完了すると動的に内容がクリアされます。

実 態 は、org.codehaus.groovy.grails.web.servlet.GrailsFlashScopeです。

次の例では、index アクションにリクエストを受けると flash.

message にメッセージを代入して、home アクションにリダイレ
クト、home アクションで処理されるビューで flash.message が参照できます。そして処理が完了すると、flash はクリアされます。
def index = {flash.message = "Hello!"
redirect(action:home)}
def home = {//}■params

前半でも簡単に紹介した、リクエストパラメータを収納している変数です。公式ドキュメントでは、ミュータブル多次元ハッシュマ ッ プ と 説 明 さ れ て い ま す。 ク ラ ス の 実 態 は、org.codehaus.
groovy.grails.web.servlet.mvc.GrailsParameterMap です。
参照方法の簡単な例です。

変換を使用します。

def num = params.int('num')if(num){println num+10}
params.num であれば文字列の場合でも if 文を通ることができ

ますが、params.int('num') と指定する事で、数値以外であれば確

実に null を返すようになるので、条件を通ることができません。
このように、params 型変換（null セーフコンバータとも呼ぶ）を使用することで処理を無駄なく確実にします。

通常 Web リクエストは主に文字列でパラメータから受け取る

ので、型検証や変換を予め行う必要があります。その処理をわかりやすくシンプルに記述できます。int の他に boolean、long、
char、short が使用できます。

この型変換には同じ名称のパラメータを配列に変換する

リ ス ト 変 換 も 存 在 し ま す。 リ ク エ ス ト の 内 容 が、/home/index?key=apple&key=lemon の用に同じ名称が複数存在する物を処理するには次のように記述します。
def keys = params.list('key')
keys.each{println it}
params.key と取得しても確実にリクエスト内容に "key" が複数
Grails をコントロールせよ！ Part 1

8

G*Magazine vol.1
存在するのであれば、リストとしても取得できるのですが、もし"key" が 1 個のみの場合はリストにならないので、その場合の処理を正確に記述するために使えます。

// リクエストが /index?key=apple の場合は。
def keys = params.key//keys は String になる。

// リクエストが /index?key=apple&key=lemon の場合は。

def keys = params.key //keys は配列になる。

def keys = params.list('key') // リクエスト内容の数に関係無く確実に配列になる。

●params の基本とバインディングの基本

先ずはじめに単純な使用方法の例をおさらいします。リクエス

ト 内 容 が、/home/index?username=tyama&age=27&email=tyama@xmldo.jp とすると、アクションの内部で、params から簡単に取得できました。

def username = params.username
def email = params.email
ドメインクラス User を例として、▼User.groovyclass User {String username
String password
String email
int age}
先ほどのパラメータ内容をドメインクラスにバインドする場合

は、次のようにするのではなく。
def user = new User()user.username = params.username
user.email = params.email
ドメインにリクエストパラメータをバインドさせるには、単純と思います。
●パラメータ指定でセキュリティ向上

データバインディングの問題点として、リクエストに更新を行うべきでない不正なパラメータも付加されてしまった場合でも、自動でセットしてしまうという懸念があります。それを制御するために、不用なパラメータのバインディングを行わないよ

うにするために、properties にバインディングを行いたいフィールドを指定する方法があります。この例ではリクエストとして、
username、email の他に不正に付加して password が含まれているとします。user.properties['username','email'] と指定する事で、不用なパラメータ password は、params からバインドされることはありません。

def user = User.get(1)user.properties['username','email'] = params
bindData を使用した例。
def user = new User()bindData(user, params, [ include:['username','email'] ])// 除外する場合は。

bindData(user, params, [exclude:'password'])
自動生成されるスカッフォルドのコードについては、このような対策がされていません。スカッフォルドで生成したコードを重要箇所にそのまま使用することは無いとは思いますが、それも含
めて、セキュリティを重要視するモデルに対してのバインディン
グには必ずこの方法を使用しましょう。

今回はここまでです。今回はコントローラの基礎から、リクエ

ストの処理から、簡単なバインディングまで解説しました。いよいよ、次回はリレーショナルのあるドメインのバインディング、
コマンドオブジェクト、REST、コントローラにまつわる制御の仕組み、GSP、URL マッピングを解説します。ではまた次号でお会いしましょう！

に params を constructor に与えるか、properties に代入するだけです。

def user = new User(params)// またはdef user = new User()user.properties = params
bindData メソッドでバインディングを行うこともできます。
def user = new User()bindData(user, params)※但しデータバインドは、内部で自動でバインドを行うために速度的な懸念もあります。従って先に挙げた例も間違いではありませんので、速度を検証してみて使いやすい方を選ぶのも良いと思います。個人的意見では、間違った代入や、コードの見やすさを考えると Grails が提供するデータバインドを使用した方が良い
Grails をコントロールせよ！ Part 1

9G*Magazine vol.1

Griﬀon 不定期便

〜第 2 回 バインディング編〜
奥 清隆（おく きよたか）

series02

仕事でもときどき Groovy と戯れるプログラマ。
日本 Grails/Groovy ユーザーグループ関西支部長。
著書：『Seasar2 による Web アプリケーションスーパーサンプル』

今回は Griffon でのバインディングについて紹介します。バインディングについては前回少し紹介しましたが、今回はもう少し深く紹介します。

Griffon のバインディングといっても基本的な機能は Groovyの SwingBuilder で 提 供 さ れ て い ま す。 今 回 は Griffon と い う より Groovy の SwingBuilder の 話 が 中 心 に な っ て し ま い ま す が、SwingBuilder は Griffon でも重要な機能ですので、SwingBuilderを使った様々なバインディングを紹介したいと思います。

■ビューからモデルへのバインディング

テキストフィールドに入力された値をモデルにバインディング

させてみましょう。次のようなサンプルコードでビューからモデルへのバインディングを確認します。SwingBuilder の機能しかこのテキストフィールドに名前を入れてボタンをクリックするとダイアログが表示されます。

使っていませんので GroovyConsole に貼付けて実行する事ができます。

import groovy.swing.SwingBuilder
import groovy.beans.Bindable
class Model {@Bindable name}

シンプルな例ですが、ポイントは Model クラスのプロパティ

def model = new Model()new SwingBuilder().edt {frame(show:true, pack:true) {gridLayout(cols:1, rows:2)
textField(text:bind(target:model,
targetProperty:'name'))button('Hello', actionPerformed: {optionPane(message:"Hello,${model.name}!").
createDialog('Message').show()})}}
このサンプルを実行すると次のようなアプリケーションが起動で宣言している @Bindable アノテーションと、テキストフィール

ドの text プロパティで bind メソッドを使用している 2 点です。この 2 点でテキストフィールドの値が変更されるとモデルに反映されるようになります。

このバインディングは次のように少し省略して書く事もできます。

textField(text:bind(target:model, 'name'))■モデルからビューへのバインディング

今度は逆にモデルからビューへのバインディングを見てみましょう。

ここではボタンをクリックすると、運勢を占ってくれるおみく

じアプリを作ってみましょう。

このサンプルも GroovyConsole 上で実行できます。

します。

Griffon 不定期便 〜第 2 回 バインディング編〜

10

G*Magazine vol.1

import groovy.swing.SwingBuilder
import groovy.beans.Bindable
def FORTUNE_TEXTS = [' 大吉 ', ' 吉 ', ' 中吉 ', ' 小吉', ' 末吉 ', ' 凶 ']■双方向のバインディング

テキストフィールドなどの入力コンポーネントを使用していると同じプロパティを使ってモデルからビューへ、
そしてビューからモデルへと双方向のバインディングが必要になる場合もあります。
これまでのサンプルで source と target プロパティを使用したので次のように記述すれば双方向のバインディングができるように思うかもしれません。

class Model {@Bindable fortune}

textField(text:bind(sourceProperty:'value', targetProperty:'value', target:model,

def model = new Model()source:model))
しかし、これでは期待した結果は得られません。モデルから

new SwingBuilder().edt {frame(title:' おみくじ ', show:true, pack:true)

ビューへのバインディングとビューからモデルへのバインディン

グがループしてしまい StackOverflowError が発生してしまいます。
次のように、mutual プロパティを指定することで双方向のバ{
gridLayout(cols:1, rows:2)

インディングが可能になります。

label(text:bind(source:model,
sourceProperty:'fortune'))button('click', actionPerformed: {model.fortune = " 今日の運勢 :${FORTUNE_TEXTS[(int) (FORTUNE_TEXTS.size() * Math.random())]}"})}}
実行結果は次のようになります。ボタンをクリックする事で運勢が表示されます。

textField(text:bind(targetProperty:'value',
target:model, mutual:true))■ビューからビューへのバインディング

すべてのバインディングをモデルとビューの間で簡単にできるのは便利ですが、わざわざモデルにプロパティを持たせるまでもない（あるいは持たせたくない）
ようなバインディングもあります。
たとえば、ラジオボタンの選択によって他の入力コンポーネン

トの状態を変える場合を考えてみます。

import groovy.swing.SwingBuilder
import groovy.beans.Bindable
class Model {@Bindable String text}
def model = new Model()最初のビューからモデルへのバインディングと似ていますが、今回は bind メソッドの引数に source と sourceProperty を指定することでビューへのバインディングになっています。

new SwingBuilder().edt {frame(title:' アンケート ',show:true,pack:true){
gridLayout(cols:1, rows:6)

label ' 今回の G*Magazine は？ 'label(text:bind(source:model,

buttonGroup(id:'bg')

sourceProperty:'fortune'))radioButton 'とても良かった', buttonGroup:bg

radioButton ' 良かった ', buttonGroup:bg

このコードも次のように省略形で記述する事ができます。

radioButton id:'other', ' その他 ', buttonGroup:bg

label(text:bind(source:model, 'fortune'))textField(text:bind('text', target:model),editable:bind(source:other,bind メソッドで source を指定する場合は、クロージャを使用

sourceEvent:'itemStateChanged',

してさらに省略する事ができます。

label(text:bind { model.fortune })sourceValue: {other.selected}))}}Griffon 不定期便 〜第 2 回 バインディング編〜

11

G*Magazine vol.1
このサンプルを実行すると次のようになります。

import groovy.swing.SwingBuilder
import groovy.beans.Bindable
class Model {@Bindable Date now}
def model = new Model()model.now = new Date()
new SwingBuilder().edt {frame(id:'frame', show:true, pack:true) {gridLayout(cols:6, rows:1)
label(text:bind('now', source:model,

よくあるアンケートの入力フォームですが、ラジオボタンで「そ

converter: {it.format('yyyy')}))の他」を選んだ場合だけテキストを自由に入力することができる

label(' 年 ')ようになります。

label(text:bind('now', source:model,

モデルにテキストフィールドの編集可能かどうかを判定するプ

converter: {it.format('MM')}))

ロパティを持たせる事もできますが、モデルで持つほどのものでlabel(' 月 ')もないのでラジオボタンの選択によってテキストフィールドの状

label(text:bind('now', source:model,

態を変えています。

converter: {it.format('dd')}))

sourceEvent、sourceValue という新しいプロパティを bind メlabel(' 日 ')ソッドに指定しました。また、sourceProperty は指定していませ

}

ん。

}

イベントでバインディングさせる事が可能になります。また、実行結果は次のとおりです。

sourceEvent を 指 定 す る 事 で source オ ブ ジ ェ ク ト の 任 意 のsourceValue を指定すると source とは異なるオブジェクトからバインディングさせる事が可能になります。

■変換処理

バインディング時に変換処理を間に入れることも可能です。例

えば、日付の年月日をそれぞれ別のコンポーネントに表示させる
ような場合、年月日の 3 つのプロパティをモデルに持たせるのは冗長で、コントローラなどからも扱いづらくなってしまいます。
そんな場合はモデルに 1 つだけ Date 型のプロパティを定義しておきビューの各コンポーネントでは converter プロパティを指定することで変換した値を表示させる事ができます。

converter は sourceValue と似ていますが、converter で指定するクロージャには sourceProperty の値が引数で渡されます。逆にsourceValue のクロージャには引数が渡されませんので任意の値を使用する事ができます。

■バリデーション

変換処理が必要になってくると、ビューからモデルへのバイン

ディング時に入力値のバリデーションも欲しくなってきます。モ

デルのすべてのプロパティを String 型にしてしまう方法もありますが、とても扱いづらくなってしまうでしょう。バリデーションの実装も簡単にできます。

Griffon 不定期便 〜第 2 回 バインディング編〜

12

G*Magazine vol.1

import groovy.swing.SwingBuilder

package sample

import groovy.beans.Bindable
import groovy.beans.Bindable
import griffon.beans.Listenerclass Model {@Bindable String postCode@Listener(loggingListener)}class ListenerSampleModel {def model = new Model()@Bindable String value1@Bindable String value2

new SwingBuilder().edt {frame(id:'frame', show:true, pack:true) {def loggingListener = {gridLayout(cols:1, rows:2)

println "${it.propertyName}:

textField(text:bind('postCode',${it.oldValue} -> ${it.newValue}"

target:model, validator:{}

it ==~ /\d{3}-\d{4}/}}))button('click', actionPerformed: {optionPane(message:model.postCode).
createDialog('Message').show()})}}
validator プロパティで入力値を検証するクロージャを定義するだけです。このクロージャが false を返した場合、ビューの表示はそのままですがモデルには値が反映されません。入力値がエラーになる場合は何らかの通知をユーザに対して行う必要があります。

サンプルのバリデーションは簡単なものですが、実際にアプ

リケーションを作成すると Grails のドメインクラスの様なバリデーションが欲しくなってくると思います。SwingBuilder では

Grails の様なバリデーションは提供されていませんが、Griffonのプラグインとして Validation プラグインが提供されています。
Validation プラグインについては後述します。

■PropertyChangeListener を追加する

こ こ ま で は SwingBuilder の バ イ ン デ ィ ン グ 機 能 を

紹 介 し て き ま し た が、Griffon で は バ ー ジ ョ ン 0.9 か ら

PropertyChangeListener を追加する Listener アノテーションが提供されています。

Listener アノテーションとリスナー用のクロージャを定義する事で PropertyChangeListener を簡単に追加する事ができます。

Validation プラグイン
ここでは Griffon の Validation プラグインを紹介します。バリデーションについては SwingBuilder の機能でもできない事はありませんが、Grails の様な豊富なバリデーションと入力エラーを通知するのにこのプラグインが利用できます。

■アプリケーションの作成とプラグインのインストール

今のところ Validation プラグインは Griffon のバージョン 0.9 にしか対応していませんので、Griffon 0.9 でサンプルアプリケー
ションを作成していきます。

$ griffon create-app validationsample
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Welcome to Griffon 0.9 - http://griffon.codehaus.
org/
Licensed under Apache Standard License 2.0
Griffon home is set to: /usr/local/griffon/
current...
プラグインをインストールします。
$ cd validationsample$ griffon install-plugin validation...

■モデルの編集

griffon-app/models/validationsample/ValidationsampleModel.

groovy を編集していくつかのプロパティと制約を追加します。

Griffon 不定期便 〜第 2 回 バインディング編〜

13

G*Magazine vol.1

package validationsample
import groovy.beans.Bindable
class ValidationsampleModel {@Bindable String requiredText@Bindable String url@Bindable String email@Bindable String hoststatic constraints = {■ビューの編集作 成 し た モ デ ル を テ ス ト す る た め に griffon-app/views/

validationsample/ValidationsampleView.groovy を 変 更 し ま し ょう。

package validationsample
import net.sourceforge.gvalidation.swing.
ErrorMessagePanelapplication(title: 'Validation Sample',size: [600,300],

requiredText(blank:false)

locationByPlatform:true,url(url:true)

iconImage: imageIcon('/griffon-icon-48x48.png').image,email(email:true)

iconImages: [imageIcon('/griffon-icon-48x48.png').image,host(inetAddress:true)

imageIcon('/griffon-icon-32x32.png').image,}

imageIcon('/griffon-icon-16x16.png').image]) {}tableLayout {tr {制約の指定方法は Grails のドメインクラスと同じです。

td(colspan:2) {widget(new ErrorMessagePanel(messageSource),
id: 'errorMessagePanel', errors: bind(source: model, 'errors'))}}tr {td(align:'right') { label 'Not blank' }td{textField(text:bind('requiredText',target:model),columns:30)}}
tr {td(align:'right') { label 'URL' }td{textField(text:bind('url', target:model), columns:30) }}tr {td(align:'right') { label 'Email' }td{textField(text:bind('email', target:model), columns:30) }}tr {td(align:'right') { label 'Host' }td{textField(text:bind('host', target:model), columns:30) }}tr {td(colspan:2){button('validate',actionPerformed:{model.validate()})}}}}
ErrorMessagePanel クラスは Validation プラグインで提供されているエラーを通知するための簡単なコンポーネントです。ボタンをクリックしたときにモデルの validate メソッドを呼び出してバリデーションを行います。この validate メソッドは Validation
プラグインによって拡張されたもので、モデルにエラーがあった場合、errors というプロパティにエラー情報が格納されます。
Griffon 不定期便 〜第 2 回 バインディング編〜

14

G*Magazine vol.1
ErrorMessagePanel にモデルの errors をバインディングする事でエラー情報をビューで通知する事が可能になります。

セージが表示されます。

■エラーメッセージの追加

griffon-app/i18n/messages.properties にエラーメッセージを追加します。今回は Validation プラグインのドキュメントページのエラーメッセージをそのまま追加します。

default.matches.message=Property [{0}] of class [{1}] with value [{2}]does not match the required pattern [{3}]default.url.message=Property [{0}] of class [{1}] with value [{2}] is
not a valid URL
default.creditCard.message=Property [{0}] of class [{1}] with value[{2}] is not a valid credit card number
default.email.message=Property [{0}] of class [{1}] with value [{2}]is not a valid e-mail addressdefault.range.message=Property [{0}] of class [{1}] with value [{2}]まとめ
今回は Griffon でよく使うバインディングを紹介しました。バインディングを理解する事で MVC 間での情報のやりとりも、よりスマートな形で実装する事ができるようになります。次回はスレッドについて紹介したいと思います。それではまた、お会いしましょう。

does not fall within the valid range
default.size.message=Property [{0}] of class [{1}] with value [{2}]does not fall within the valid size
default.max.message=Property [{0}] of class [{1}] with value [{2}]exceeds maximum value [{3}]default.min.message=Property [{0}] of class [{1}] with value [{2}] isless than minimum value [{3}]default.maxSize.message=Property [{0}] of class [{1}] with value [{2}]exceeds the maximum size of [{3}]default.minSize.message=Property [{0}] of class [{1}] with value [{2}]is less than the minimum size of [{3}]default.validator.message=Property [{0}] of class [{1}] with value[{2}] does not pass custom validation
default.inList.message=Property [{0}] of class [{1}] with value [{2}]is not contained within the list [{3}]default.blank.message=Property [{0}] of class [{1}] cannot be blankdefault.notEqual.message=Property [{0}] of class [{1}] with value [{2}]cannot equal [{3}]default.nullable.message=Property [{0}] of class [{1}] cannot be null

■アプリケーションの実行

それではアプリケーションを実行してみましょう。

griffon run-app
実行すると以下のようになります。

ボタンをクリックしてエラーがあると以下のようにエラーメッ
Griffon 不定期便 〜第 2 回 バインディング編〜

15

G*Magazine vol.1

CodeNarcを利用してGROOVYのコード品質を上げる〜第 1 回 CodeNarcとは〜
series03

荒井健太郎

某 IT ベンダーのセキュリティコンサルタント、ソフトウエアをよりセキュアにするために日々精進しています。
テスト系スクリプトは、G* を利用して書いています。

静的コード解析とは因となるコードの一部分はパフォーマンステスト等で発見できる

Codenark は、Groovy で作成された、Groovy 向けの静的コー

ド解析ツールである。

静的コード解析は、プログラムを実行せずにソースコードを構造的に解析し、一般的に知られているコードの問題が解析対象のソースコードに存在していないかをチェックすることである。こ
こでいう一般的に知られているコードの問題は、拡張性低下の原因となるコード、性能劣化の原因となるコード、セキュリティの脆弱性を持つコードやコーディング規約に準拠していないコード

かもしれないが、それは問題の一部分である。

テストと静的コード解析は目標としていることが本質的に違う。テストは、バグすなわち設計上の問題点を検出することを目標としている。すなわち、ユーザの要件通りにソフトウエアが実行されることを検証している。一方、静的コード解析は、コードの品質が高いかの検証、すなわち、非機能要件について検証をしている。設計上の問題とコードの問題のイメージは下図のようになる。

を指す。オープンソースの静的コード解析ツールとして、Java 向けに、｢PMD（http://pmd.sourceforge.net/）｣、｢CheckStyle（http://
checkstyle.sourceforge.net/）｣、｢FindBugs（http://findbugs.

sourceforge.net/）｣ や ｢Jlint（http://jlint.sourceforge.net/）｣ などがある。これらのツールの違いは、「どのようなコードの問題を検証するのが得意か」という点で異なっている。FindBugs やJlint は、潜在的なバグを検証することを主眼としている。一方、CheckStyle はコーディング規約（コメントの書き方等）の問題を検証することを主な目標としている。PMD は汎用的な（幅広い）問題を検証することを目標としている。Groovy 向けの静的コー
ド 解 析 ツ ー ル と し て、IntelliJ IDEA（http://www.jetbrains.com/
idea/）にバンドルされた静的コード解析ツールがある。

このツールは、IDE の IntelliJ 上で静的コード解析を実行することを目標としている。

PMD、CheckStyle や IntteliJ IDEA にバンドルされた静的コード

解析ツール の影響を受けて開発されていることを考慮すると、
CodeNark は、汎用的な問題を検証し、汎用的な用途で利用でき

る静的コード解析ツールを目標としていると考えることができる。

また、静的コード解析はプログラムを実行することなく実行することができるので、単体テスト、結合テストなどのテストより前、コードを 1 行書き始めた時から実行することが可能である。
したがって発見された問題点による手戻りが少なくなるというメ

リットがある。参考までに、ソフトウエア開発の工程で手戻りが発生した場合のコストの例を以下に示す。出典は、｢Soo Hoo,

Kevin, Andrew W. Sudbury, and Andrew R. Jaquith. "Tangible ROI
through Secure Software Engineering." Secure Business Quarterly.
1-2. 2001.｣ である。

また、商用の静的コード解析ツールとしては、｢Fortify SCA（https://www.fortify.com/）｣、｢Coverity（http://www.coverity.
com/html_ja/）｣ などがある。オープンソースと商用の差は、結果の表示手法の違い、コード解析の深さの違い（ファイルやクラス間にまたがるデータフローを解析できるか等）やルールの違い（* ルールについては後述）などがある。Groovy のコードを解析することが可能な商用の静的コード解析ツールは私が調査した限りでは存在しない。

設計上の問題とコードの問題
前述した一般的に知られているコードの問題は、単体テスト

や結合テストと呼ばれるテストでみつけるものだと考える方が多
いかもしれない。

しかし、テストのみで拡張性の低下となるコードや性能劣化の静的コード解析ツールのまとめ
以上をまとめると、静的コード解析はテストで検証することが難しいコードの問題を検証し、開発の早い段階で問題点を検証できるということである。

原因となるコードが発見できるだろうか。たしかに性能劣化の原
CodeNarc を利用して groovy のコード品質を上げる〜第 1 回

CodeNarc とは

16

G*Magazine vol.1

CodeNarc のルール

CodeNarc のダウンロード

CodeNarc は、一般的な静的コード解析ツールと同様に静的

http://sourceforge.net/projects/codenarc/files/

から

コード解析をルールに従って実施する。解析に使用するルールはCodeNarc-（バージョン番号）-bin.zip のファイルをダウンロー

従って作成したルールを使用することができる。静的解析ごとに使用するルールを切り替えることも可能である。

コマンドランインからの実行

sourceforge.net/codenarc-rules-basic.html の左メニューの Rules

ルとして実行する。その際に、以下を設定する必要がある。

CodeNarc に標準で付属しているルール及び CodeNarc の仕様に

CodeNarc に標準で付属しているルールは、http://codenarc.

から参照することが可能である。

ドし任意のディレクトリに解凍する。

コマンドラインからの実行は、CodeNarc を Java の実行ファイ• Groovy の Jar ファイル

• CodeNarc の jar ファイル

このコラムの内容
第 1 回は、CodeNarc の基本的な実行方法を紹介し、第 2 回以

• Log4J の jar ファイル

CodeNark に付属している sample に対して静的コード解析を実降でルールのカスタマイズ方法や各種プラグインの利用方法を紹行する例は次の通りである。

■基本的な実行方法

RunCodeNarc.bat を編集する。

介する。

CodeNarc を実行するためには、以下のものを用意しておく必要がある。Log4J のバイナリが CodeNarc に付属していることを考慮すると、Groovy の実行環境を構築している方であれば、CodeNarc をダウンロードすれば他に用意するものはない。
• Groovy 1.7 以上（展開したディレクトリ）\samples\ に移動し、以下のように@set GROOVY_JAR="%GROOVY_HOME%/embeddable/groovyall-1.7.6.jar"
java -classpath %GROOVY_JAR%;../CodeNarc-0.12.
jar;../lib/log4j-1.2.13.jar org.codenarc.CodeNarc-title=HelloCodeNarc %*• Java1.5 以上• Log4J1.2.13 以降（CodeNarc の tarball に付属）

1 行目は、groovy の jar ファイルの場所を指定している。2 行

CodeNarc は、コマンドラインからの実行以外にも様々な実行

目は、CodeNarc の jar ファイルの位置、Log4J の jar ファイルのう観点から、CodeNard に付属しているサンプルを利用して、「コ

CodeNarc のオプションは以下の表の通りである。オプションをする。ここでは、windows 環境に groovy の環境設定が終了してする。

方法がある。今回は、CodeNarc の基本的な動作を理解するとい位置及び CodeNarc のオプションを指定している。指定可能な

マンドラインからの実行」と「Ant タスクとしての実行」を紹介

指定しなかった場合は、表に記述してあるデフォルトの値で動作

いる、CodeNarc-0.12 を利用している前提で話を進める。
パラメータ

説明

例

デフォルト

-basedir=DIR

解析対象のベースディレクトリを指定する。

-basedir=src/main/groovy

カレントディレクトリ (.)-includes=PATTERNS

解析対象ファイルのパターンを Ant 形式で指定する。

-includes=**/*.gr.groovy ファイルすべて（**/*.groovy）-excludes=PATTERNS

解析対象からはずすファイルのパターン
を Ant 形式で指定する。

-excludes=**/templates/**,**/*Test.*

指定なし-rulesetfiles=FILENAMES

解析するルールを指定する。このオプ
ションでルールの ON-OFF をルールセッ
ト単位で指定できる。

-rulesetfiles=rulesets/imports.xml,
rulesets/naming.xml

rulesets/basic.xml-report=REPORTTYPE[:FILENAME]

結果の出力形式を TYPE[:FILENAME] で指定する。

-report=html-report=html:MyProject.html-report=xml-report=xml:MyXmlReport.xml-report=org.codenarc.report.
HtmlReportWriter

html

TYPE は、"html", "xml", "text", "console"のいずれかで設定する。出力タイプを独自に定義した場合は、定義したクラスを指定することが可能である。
（例：org.
codenarc.report.ReportWriter）
FILENAME は出力ファイルのファイル名を指定する。
-title=REPORT TITLE

出力するプロジェクト名を指定する。

-title="My Project"

指定なし

-help

この表のヘルプを表示する。

-help

指定なし

CodeNarc を利用して groovy のコード品質を上げる〜第 1 回

CodeNarc とは

17

G*Magazine vol.1
編集した bat ファイルを実行すると、実行したディレクトリ直下に、｢CodeNarcReport.html｣ が作成される。このファイルをブラウザ等で開くことによって、以下のような分析結果を参照す
ることが可能である。

イルを設定している。
▼RunAntTask.bat
set GROOVY="%GROOVY_HOME%\embeddable\groovy-all1.7.6.jar"
set CODENARC_JAR=../CodeNarc-0.12.jar
set LOG4J_JAR=../lib/log4j-1.2.13.jar
ant -lib %CODENARC_JAR% -lib %GROOVY% -lib
%LOG4J_JAR% -lib lib runCodeNarc
ant –lib オプションで、Groovy の Jar ファイル、CodeNarc の jar

ファイル及び Log4J の jar ファイルを指定している。

編集した bat ファイルを実行すると、実行したディレクトリ直下 に、｢reports｣ デ ィ レ ク ト リ が 作 成 さ れ、｢CodeNarcReport.

Ant タスクとしての実行

html｣ が作成される。このファイルをブラウザ等で開くことにAnt のタスクとして CodeNarc を実行することが可能である。

Ant タスクは、build.xml に CodeNarc エレメント、report エレメ

ント及び fileset エレメントを記述することによって定義する。各
エレメントの詳細は、http://codenarc.sourceforge.net/codenarcant-task.html

を参照のこと。定義したエレメントを実行する

際は、コマンドラインから実行するときと同様に ant –lib オプ

ションで、Groovy の Jar ファイル、CodeNarc の jar ファイル及び
Log4J の jar ファイルを指定する必要がある。

CodeNark に付属している sample に対して、Ant タスクを利用して静的コード解析を実行する例は次の通りである。

( 展開したディレクトリ）\samples\ に移動し、以下のように、build.xml 及び RunAntTask.bat を編集する。

よって、コマンドラインからの実行と同様に分析結果を参照する
ことが可能である。

まとめ
今回は、静的コード解析ツールのメリットと、Groovy 向けの静的コード解析ツール CodeNarc の基本的な操作方法を解説した。CodeNark の操作方法はそれほど難しくないと感じて頂けたと考えている。

CodeNark は、静的解析に利用するルールのカスタマイズ機能や各種開発管理ツールと連携する機能を持っている。これらの機能を利用することによってより現実の開発プロセスに静的コード
解析を取込みやすくなる。次回以降は、これらの機能を紹介させて頂ければと考えている。

▼build.xml

おまけjggug 合 宿 で 制 作 し た wiki(https://github.com/jggug/simple-<project name="HelloCodeNarc" ><taskdef name="codenarc" classname="org.codenarc.ant.CodeNarcTask"/>wiki）に対して、CodeNark の basic ルールセットを利用して静的コード分析を行った結果は、以下の通りである。

CodeNarc で分析した結果は、問題はみつからなかった。ルー<target name="runCodeNarc">

ルセットを変えると問題がみつかる可能性がある。

<mkdir dir="reports"/><codenarc
ruleSetFiles="rulesets/basic.xml,rulesets/
exceptions.xml,rulesets/imports.xml,rulesets/braces.xml"><report type="html"
toFile="reports/CodeNarcAntReport.html"
title="My Sample Code"/><fileset dir="src"><include name="**/*.groovy"/></fileset></codenarc><echo message="Done."/></target></project>codenarc エレメントで解析に使用するルールを指定、report

エレメントで出力形式を指定、fileset エレメントで解析対象ファ
CodeNarc を利用して groovy のコード品質を上げる〜第 1 回

CodeNarc とは

18

G*Magazine vol.1

GebではじめるWebテスト〜第 1 回 導入編〜
series04

綿引 琢磨（わたびき たくま）

Groovy/Grails/Griﬀon/Java 界隈のやさぐれエンジニア。
日本 Grails/Groovy ユーザーグループ運営委員。

はじめに読者の皆さんは、普段 Web アプリケーションでの機能テスト

はどのように行っていますか？今日では商用・OSS を問わず、様々な Web アプリケーション向けのテストツールが存在しています

ので、既に Web 機能テストを自動化している方も多いと思いま
すが、まだまだ手動で実施している方もいるのではないでしょうか。また、テストツールを導入したものの、プロジェクトの開発
手法に合わなかったり、テストスクリプトを修正するコストが高
く、保守されなくなってしまったケースもあるかもしれません。
本稿では、Groovy を用いた Web アプリケーション向けの機能

テストライブラリである Geb（「ジェブ」と発音します）を用いた Web テストの実施方法を紹介していきます。Geb はアジャイ

ル開発と相性が良く、簡潔な DSL でテストスクリプトを記述する// ページ上の全ての 'div' 要素を取得$("div")// ページ上の最初の 'div' 要素を取得$("div", 0)// ページ上のタイトル属性の値が 'section' である全ての'div' 要素を取得$("div", title: "section")// ページ上の class 属性が 'main' である全ての 'div' 要
素を取得$("div.main")

ことのできるテストライブラリですので、これから Web テスト●Page Object パターン

不満のある方にもお勧めのライブラリです。

のオブジェクトとして表現し、テスト対象となる画面上の UI コ

を解説していきます。

らすことができますし、UI が変更された場合にもコードの修正

Geb とはとができます。

の自動化を検討している方や、現在利用しているテストツールに初回は導入編として、Geb の概要とインストールから実行まで

Page Object パターンでは Web アプリケーションの画面を一連

ンポーネントをモデル化します。これにより重複したコードを減が少なくなりますので、変更に強く再利用性の高い実装をするこ

Geb は、Luke Daley 氏 を 中 心 に 開 発 さ れ て い る Web ア プ リ

ケーション向けの機能テストを自動化するためライブラリです。
Internet Explorer, FireFox, Chrome などのブラウザを操作することが可能な Selenium の WebDriver と JQuery ライクな記述でコンテンツの操作や検査を可能にする API を組み合わせ、Groovy の豊

かな表現力により簡潔な DSL でテストスクリプトを記述することができます。

また、JUnit や Spock などのテストフレームワークと統合することも可能なため、TDD や BDD などの開発プロセスに取り入れやすいですし、使用するブラウザによってはテスト中の画面をキャプチャして出力する機能も提供されていますので、開発者が機能テストやシナリオテストを効率良く行うことができます。

■Geb のコンセプト

Geb は冗長な記述を排除し、より簡単に Web テストを書くことを実現するために、次の２つの概念を取り入れています。

■Geb を使用するメリット

OSS だけでも Web アプリケーション向けのテストツールは数多くあります。その内、現在主流と思われる Selenium、Canoo
WebTest と比較しながら Geb を使用するメリットを示します。
●Selenium との比較

Selenium はキャプチャ／プレイバックツールにカテゴリされ●jQuery ライクなコンテンツ操作・検査 API

るテストツール※です。Selenium では実際のブラウザ上でアプうことができ、今日では JavaScript ライブラリのデファクトスタ

ドを追加してあとで再生してテストを行います。このキャプチャ

jQuery は DOM の階層構造を意識せずに DOM 操作を容易に扱ンダードとなっているライブラリです。Geb は Web 開発者に馴
染みのある jQuery ライクな API を提供し、テストスクリプトを記述し易くしています。

リケーションを操作し、その操作記録に assert などの検証コマン／プレイバックのアプローチは、テストスクリプトが自動生成されるため一見便利なように思うかもしれませんが、問題点もあります。それは一度は手動でアプリケーションを操作しなければな
Geb で始める Web テスト〜第 1 回 導入編〜

19

G*Magazine vol.1
らないことです。つまり、事前にある程度正常に動作する状態になっていなければ、テストの実施どころか、テストのための記録も取ることができません。

一方、Geb は想定される動作をスクリプトに記述してテストを行うアプローチですので、予め UI コンポーネントのタグ名や idなどがわかっていればテストスクリプトを先に書くことができます。TDD のようにプレゼンテーション層でもテストファーストで開発することができますし、開発チームとテストチームが分かれている場合では並行して作業することもできます。

また、Geb では Selenium の WebDriver をエンジンとして使用

していることから、Selenium 同様に実際のブラウザを使用したテストを行うことができます。

※ Selenium で も キ ャ プ チ ャ ／ プ レ イ バ ッ ク 機 能 を 使 用 せ ず、Java や Groovy などでスクリプトを記述することも可能です。

●Canoo WebTest との比較

Canoo WebTest（ 以 降、WebTest） は ス イ ス の CanooEngineering AG 社により 2002 年から開発されているテストツー
ルです。Geb 同様スクリプトを記述してテストを行うアプローチを採用しており、通常はテストスクリプトは Ant のビルドファイ

ル形式で記述します。スクリプトの記述には Groovy もサポートされているため、Groovy の AntBuilder を使用して記述することもできますが、簡潔な記述とまでは言い切れません。

これに対して Geb では、前述している通り DSL により簡潔な

Hello 画面

Greeting 画面■環境設定

Geb を使用するためには、設定をいくつか行う必要があります。

●Eclipse の設定
Groovy-Eclipse プラグインのインストール

まずはじめに、Groovy-Eclipse プラグインをインストールします。使用している Eclipse のバージョンに応じたアップデートサ
イトを指定し、プラグインをインストールをしてください。
• Eclipse 3.6 の場合

http://dist.springsource.org/release/GRECLIPSE/e3.6/• Eclipse 3.5 の場合

http://dist.springsource.org/release/GRECLIPSE/e3.5/

プロジェクトの変換

次に、当該プロジェクトで Groovy のクラスファイルを扱えるようにするためにプロジェクトの変換を行います。プロジェ

クトで右クリックし、ポップアップメニュー ＞ Configure ※ ＞
Convert to Groovy Project を選択します。

記述ができますし、Page Object パターンを採用することで冗長な記述を排除することができます。簡潔で感覚的にわかりやすいスクリプトを記述できる点は、生産性や保守性を考えると大きなメリットとなります。

また、WebTest では実際のブラウザを起動するのではなく、

HtmlUnit を使用して内部的にブラウザ上の動作をシミュレート

してテストを行います。ブラウザのシミュレートは実際のブラウザが動作する環境とは異なりますが、Geb ではブラウザや動作環境に起因する問題について憂慮する必要はありません。

このように、Geb には他のテストツールにはないメリットがあります。では、実際に Geb でのテストがどのようなものか見ていきましょう。

Geb を使用した Web アプリケーションの機能テスト
今回は、Eclipse 上で開発する Java の Web アプリケーションに対して、Geb を使用して機能テストを行います。

対象のアプリケーションはいわゆる Hello World です。テキス※日本語環境では「構成」です。

トボックスにテキストを入力し【Greet】ボタンを押下すると、●Geb の設定表示される単純なものです。

なります。通常は Maven または Gradle などのビルドツールまた

次画面に入力されたテキストを含めたメッセージが <h1> タグでGeb を使用するには geb-core.jar と WebDriver の実装が必要には @Grab 経由で取得します。Geb の現時点での最新バージョン
は 0.5.1 です。ここでは pom.xml を使用して取得します。

Geb で始める Web テスト〜第 1 回 導入編〜

20

G*Magazine vol.1■Page Object パターンを適用しない実装▼xml▼WebTest.groovy<dependency><groupId>org.codehaus.geb</groupId><artifactId>geb-core</artifactId><version>RELEASE</version>

package hello;
import org.junit.Test<type>jar</type>

import geb.Browser<scope>test</scope></dependency>class WebTest {<dependency><groupId>org.seleniumhq.selenium</groupId>@Test<artifactId>selenium-firefox-driver</artifactId>

void helloJGGUG() {<version>RELEASE</version>

Browser.drive('http://localhost:8080/Hello') {<type>jar</type><scope>test</scope>// Hello 画面が表示されていること</dependency>

assert title == 'Hello'●テストフレームワークの設定// テキストボックスに「JGGUG」と入力

Geb のテストを Eclipse から実行するために、ここでは JUnit を// Greet ボタンを押下使用します。

$('form').username = 'JGGUG'▼xml

def greetButton = $('input', name:'greet')greetButton.click()<dependency><groupId>junit</groupId>// Greeting 画面に遷移すること<artifactId>junit</artifactId>

assert title == 'Greeting'<version>RELEASE</version><type>jar</type>// 「Hello, JGGUG!」とメッセージが表示されること<scope>test</scope>

assert $('h1').text() == 'Hello, JGGUG!'</dependency>}}

テストケース}このアプリケーションに対して、次のテストを行います。
テスト条件

入力値

テスト手順

期待する結果Hello 画面が表示されていること

JGGUG

1. テキストボッ
クスに入力

Greeting 画面に遷移すること2.Greet ボタン
を押下

Hello, JGGUG! とメッセージが表示されることテストスクリプトの実装
早速、前述のテストケースを実装してみます。ここでは Page

Object パターンを適用する実装と適用しない実装の２例を紹介■Page Object パターンを適用する実装

Page Object パターンでは画面を１つのオブジェクトとして表現します。Hello 画面に対する Page クラスは次のようになります。
▼HelloPage.groovy
package pages
import geb.*class HelloPage extends Page {static url = 'http://localhost:8080/Hello'

します。

static at = { title == 'Hello' }static content = {username { $('form').username }greetButton(to:GreetingPage) {$('input', name:'greet')}}}

Geb で始める Web テスト〜第 1 回 導入編〜

21

G*Magazine vol.1
Greet 画面に対する Page クラスも同様です。
▼GreetingPage.groovy
package pages

テストの実行テ ス ト の 実 行 は、Eclipse に 統 合 し た Server を 起 動 し て お きJUnit テストを実行します。結果は JUnit ビューに表示されます。

import geb.*class GreetingPage extends Page {static at = { title == 'Greeting' }static content = {h1Text { $('h1').text() }}}これらの Page クラスを適用したテストの実装は次のようになります。

▼WebTestWithPageObject.groovy
package hello
import org.junit.Test
import geb.Browser
import pages.*class WebTestWithPageObject {テストフレームワークとの統合
ここまでは、JUnit を使用してテストを実装してきましたが、Geb にはテストフレームワークと統合するための jar が別途用意されていますので、こちらも試してみましょう。
pom.xml に次の設定を追加してください。

▼xml<dependency><groupId>org.codehaus.geb</groupId>@Test<artifactId>geb-junit4</artifactId>

void helloJGGUG() {<version>RELEASE</version>

Browser.drive(HelloPage) {// Hello 画面が表示されていること
assert at(HelloPage)<type>jar</type><scope>test</scope></dependency>
こ の geb-junit4.jar に は GroobyTestCase ク ラ ス を 継 承 し た// テキストボックスに「JGGUG」と入力

GebTest クラスと、GebTest クラスにレポート出力機能を追加しusername = 'JGGUG'

すると Browser クラスが隠蔽されるため、よりシンプルな実装と// Greet ボタンを押下
greetButton.click()// Greeting 画面に遷移すること
assert at(GreetingPage)

た GebReportingTest クラスがあります。GebTest クラスを使用なります。

@RunWith(JUnit4)class WebTestWithJUnitIntegration extends GebTest {@Testvoid helloJGGUG() {// 「Hello, JGGUG!」とメッセージが表示されること

to HelloPage

assert h1Text == 'Hello, JGGUG!'

assert at(HelloPage)}}

username = 'JGGUG'}

greetButton.click()assert at(GreetingPage)

Page Object パターンを適用すると、画面内の UI コンポーネン

トに関するコードを Page クラス内に隠蔽することができるため、

assert h1Text == 'Hello, JGGUG!'

テストスクリプトが簡潔になり感覚的にもわかりやすくなります。

}}

Geb で始める Web テスト〜第 1 回 導入編〜

22

G*Magazine vol.1■レポートの出力Firefox の WebDriver 実装を使用する場合は、GebReportingTest

クラスを継承することでテスト実行時の画面をキャプチャして出力することができます。その際にはレポート出力先のディレクト
リを指定する getReportDir() メソッドをオーバーライドする必要があります。

@RunWith(JUnit4)class WebTestWithReport extends GebReportingTest{
File getReportDir() {new File('reports')}:}
通常、レポート出力は JUnit の @After 時に出力されますが、明

示的に writeGebReport() を呼び出すことにより任意のタイミング

でレポート出力をすることもできます。テストのエビデンスとしてフォーム入力時の画面を出力したい場合などに使用すると良い
でしょう。
@Test
void helloJGGUG() {to HelloPage
assert at(HelloPage)
writeGebReport()
username = 'JGGUG'
writeGebReport()// 初期表示の状態で出力// テキスト入力後の状態で出力

greetButton.click()assert at(GreetingPage)
assert h1Text == 'Hello, JGGUG!'}
このテストクラスを実行するとレポート出力先に指定したディ

レクトリ配下にテストクラスのパッケージ名、テストクラス名のディレクトリが生成されて html と png ファイルが出力されます。

まとめ
今回は Geb の概要と Java プロジェクトへの導入までを行いました。Geb は Spock や Easyb などの BDD テストフレームワークと統合することでシナリオテストを自動化することができますし、Grails アプリケーションにプラグインとして導入することもできます。残念ながら今回は導入部分しか紹介できませんでしたが、Geb は様々な Web アプリケーションのテストに利用可能なライブラリですので、読者の皆さんにも実際に試していただいて Gebの魅力を感じていただけたらと思います。

次回は Geb が提供する主要なクラスの詳細と各種 API について紹介する予定です。ご期待ください。

レポート出力結果の画像は以下のようになります。

Geb で始める Web テスト〜第 1 回 導入編〜

23➡ Contents Index

G*Magazine vol.1

Grails Plugin 探訪
第2回~ Spock プラグイン ~URL: http://www.grails.org/plugin/spock
プラグインのバージョン : 0.5

対応する Grails のバージョン : 1.2 以上

杉浦孝博
最近は Grails を使用したシステムの保守をしている自称プログラマ。
日本 Grails/Groovy ユーザーグループ事務局長。

共著『Grails 徹底入門』、共訳『Groovy イン・アクション』

はじめに今回紹介する Grails プラグインは、Spock プラグインです。

このプラグインを組み込むことにより、Spock を使ってテスト

ケースを記述することができます。

Spock とはテストのケースの作成
本をあらわす次のドメインクラスがあります。
package pluginspockclass Book {Spock は、Java や Groovy 用のテストと仕様のためのフレーム

String title

ワークです。

Integer priceSpock については、次の URL を参照してください。
http://spockframework.org/

static constraints = {プラグインのインストール

title()
price(min: 0)

プラグインのインストール手順は、Grails のバージョンによって異なります。

■Grails 1.2.x の場合

Grails 1.2.x の場合、次のとおりです。

$ grails install-plugin spock 0.5-groovy-1.6■Grails 1.3.x の場合}}
このドメインクラスのテストケースを作成します。

ファイル自体は、test/unit ディレクトリに作成します。

クラス / ファイル名は、"Spec" あるいは "Specification" で終わる必要があります。

ここでは、test/unit/BookSpec.goorvy とします。

Grails 1.3.x の場合、次のとおりです。

$ grails install-plugin spock 0.5-groovy-1.7
または$ grails install-plugin spock
これ以降、Grails 1.3.6 を前提として説明します。

Grails Plugin 探訪

第 2 回〜 Spock プラグイン〜

24

G*Magazine vol.1

package pluginspockpackage pluginspock

import grails.plugin.spock.UnitSpec

import grails.plugin.spock.UnitSpec

class BookSpec extends UnitSpec {class BookSpec extends UnitSpec {def ' 本のタイトルで検索できる '() {def ' 本のタイトルで検索できる '() {setup:

setup:

mockDomain(Book)

mockDomain(Book)

when: ' 本の保存 'when: ' 本の保存 'new Book(title: title, Price: price).save()

new Book(title: title, Price: price).save()then: 'mockDomain を使ってタイトルで検索 'def book = Book.findByTitle(title)

then: 'mockDomain を使ってタイトルで検索 'book != nulldef book = Book.findByTitle(title)

book.title == title

book != nullbook.price == pricebook.title == title

where:

book.price == pricetitle = 'Groovy イン・アクション 'price = 3500

where:}

title = 'Groovy イン・アクション 'def 'title のバリデーション '() {price = 3500

setup:}

mockForConstraintsTests(Book)

}

when:
def book = new Book(title: title, price: 3500)

Spock プラグインでは、Spock の Specification クラスを継承しthen:

たテストクラスを提供しています。

book.validate(['title']) == validationResult

ユニットテスト用に UnitSpec というクラスがありますので、このクラスを継承してドメインクラスのテストケースを作成しま

where:

す。

title << [null, 'Groovy イン・アクション ']テストケースの実行

validationResult << [false, true]}

テストケースの実行は、test-app コマンドで実行します。

def 'price のバリデーション '() {setup:$ grails test-app

mockForConstraintsTests(Book)

Spock のテストケースだけ実行することもできます。
$ grails test-app :spockwhen:

def book = new Book(title: 'Groovy イ

ン・アクション ', price: price)then:

いろいろなテストケースクラス

book.validate(['price']) ==validationResult

Spock プラグインは、UnitSpec 以外にも、複数のテストクラス

where:

を提供しています。

price << [-1, 0, 1]

どのようなテストクラスがあるのか、簡単に説明します。

validationResult << [false, true, true]■UnitSpec

ユニットテスト用のテストクラスです。UnitSpec を継承する

テストケースは、test/unit ディレクトリに作成します。

}}

Grails Plugin 探訪

第 2 回〜 Spock プラグイン〜

25➡ Contents Index

G*Magazine vol.1■ControllerSpec

コントローラ用のテストクラスです。

ドメインクラス Book のコントローラクラス

package pluginspock
import grails.plugin.spock.ControllerSpec

package pluginspockclass BookControllerSpec extends ControllerSpec {class BookController {def 'index アクションのテスト '() {when:static allowedMethods = [save: "POST",

controller.index()

update: "POST", delete: "POST"]

then:redirectArgs.action == 'list'

def index = {redirectArgs.params.size() == 0

redirect(action: "list", params: params)}}

def list = {def 'list アクションのテスト '() {when:params.max = Math.min(params.max ?

Book.metaClass.static.list = { params ->params.int('max') : 10, 100)books

[bookInstanceList: Book.list(params),}

bookInstanceTotal: Book.count()]}

Book.metaClass.static.count = {// 以下省略}

books.size()
then:

}

controller.list() == [bookInstanceList:

に対するテストクラスは次のとおりです。ControllerSpec を継

books, bookInstanceTotal: books.size()]

承するテストケースは、test/unit ディレクトリに作成します。

where:
books = [new Book(title: 'Groovyイン・アクション', price: 3500),
new Book(title: 'Grailsイン・アクション', price: 3600),]}}■TagLibSpec

タグリブ用のテストクラスです。

ドメインクラス Book を引数にとるタグリブクラス
package pluginspockclass BookTagLib {def print = { attrs, body ->def book = attrs.bookout << "<book title=\"${book.title}\"price=\"${book.price}\">"
out << body()
out << '</book>'}}
に対するテストクラスは次のとおりです。TagLibSpec を継承するテストケースは、test/unit ディレクトリに作成します。
Grails Plugin 探訪

第 2 回〜 Spock プラグイン〜

26➡ Contents Index

G*Magazine vol.1

package pluginspockpackage pluginspock

import grails.plugin.spock.TagLibSpec

import grails.plugin.spock.IntegrationSpec

class BookTagLibSpec extends TagLibSpec {class BookServiceSpec extends IntegrationSpec {def 'book タグのテスト '() {def bookService

expect:def 'save メソッドのテスト '() {print(book: book) { ' オススメです。' } == '<book title="Groovy イン・アクション "when:

price="3500"> オススメです。</book>'

bookService.save(title, price)then:where:

Book.findByTitleAndPrice(title, price) != nullbook = new Book(title:'Groovy イン・アクション ', price: 3500)

Book.count() == 1}
where:}

title = 'Groovy イン・アクション '■IntegrationSpec

price = 3500

インテグレーションテスト用のテストクラスです。

}

サービスクラス

def 'update メソッドのテスト '() {package pluginspockwhen:
def book = bookService.save(oldTitle, oldPrice)class BookService {bookService.update(book, newTitle, newPrice)static transactional = true

then:Book.findByTitleAndPrice(newTitle, newPrice) != nulldef save(title, price) {Book.count() == 1

new Book(title: title, price: price).
save(flush: true)

where:}

oldTitle = 'Groovy イン・アクション 'oldPrice = 3500

def update(book, title, price) {newTitle = ' 改訂版 Groovy イン・アクション 'book.title = title

newPrice = 4000

book.price = pricebook.save(flush: true)
}

}
}

}
に対するテストクラスは次のとおりです。IntegrationSpec を継承するテストケースは、test/integration ディレクトリに作成します。

Grails Plugin 探訪

第 2 回〜 Spock プラグイン〜27➡ Contents Index

G*Magazine vol.1■GroovyPagesSpec

GSP 用のテストクラスです。

先述の BookTagLib#print を使用した GSP コードのテストクラスは次のとおりです。GroovyPagesSpec を継承するテストケー
スは、test/integration ディレクトリに作成します。
package pluginspock
import grails.plugin.spock.GroovyPagesSpec
class BookTagSpec extends GroovyPagesSpec {def 'print タグのテスト '() {when:template = '<g:print book="${book}">

これは良い本です。</g:print>'

params = [book: book]then:output == '<book title="Groovy イン・

アクション " price="3500"> これは良い本です。</book>'
where:

book = new Book(title: 'Groovy イン・

アクション ', price: 3500)}

GroovyGroovy は、JavaVM 上で動作する動的言語です。
URL: http://groovy.codehaus.org/
バージョン : 1.7.7, 1.8-beta-4■更新情報• 1.7.7 では、スタブ・ジェネレータや @Delegate などのバグ
フィックスや改良がいくつか行われています。
• 1.7.7 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=17020• 1.8-beta-4 では、JSON のサポートや GPars ライブラリ同梱など、バグフィックスと改良がいくつか行われています。
• 1.8-beta-4 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=17015

Griffon
Griffon は、デスクトップアプリケーションを開発するためのア
プリケーションフレームワークです。
URL: http://griffon.codehaus.org/
バージョン : 0.9.1a, 0.9.2-rc1■更新情報• 0.9.2-rc1 では、AddonManager やコントローラでの自動ス
レッド管理など、いくつかのバグフィックスと改良が行われています。
• 0.9.2-rc1 リリースノート : http://docs.codehaus.org/display/
GRIFFON/Griffon+0.9.2-rc1

Gant
Gant は、XML の代わりに Groovy で Ant タスクを記述し実行する
ビルド管理ツールです。
URL: http://gant.codehaus.org/
バージョン : 1.9.3

Gradle}

機能テストについて
Spock プラグインでは、機能テストは提供していません。機能

テスト用のプラグインとして、Geb プラグインなどがあります。

最後にSpock はとても強力なテストフレームワークですので、Grails

アプリケーションのテストケースを Spock で書いてみてはいかがでしょうか？

リリース情報 2011.02.11
GrailsGrails は、Groovy や Hibernate などをベースとしたフルスタックの Web アプリケーションフレームワークです。
URL: http://grails.org/
バージョン : 1.2.5, 1.3.6■更新情報• 1.3.6 では、beforeValidate のサポートや Spring ライブラリの更新など、いくつか新機能の追加と改良が行われています。
• 1.3.6 リリースノート : http://www.grails.
org/1.3.6+Release+Notes

Gradle は、Groovy でビルドスクリプトを記述し実行するビルド管理ツールです。
URL: http://www.gradle.org/
バージョン : 0.9.2■更新情報• 0.9.2 では、DSL の改良など、いくつかのバグフィックスと改良が行われています。
• 0.9.2 リリースノート : http://docs.codehaus.org/display/
GRADLE/Gradle+0.9.2+Release+Notes

GaelykGaelyk は、Groovy で記述する Google App Engine for Java 用のライトウェイトなフレームワークです。
URL: http://gaelyk.appspot.com/
バージョン : 0.6.1■更新情報• 0.6.1 では、プラグインのリロードに関するバグフィックスなどが行われています。
• 0.6.1 リリースノート : http://gaelyk.appspot.com/download

Google App Engine SDK for Java
Google App Engine SDK for Java は、Java で Google App Engine
用の Web アプリケーションを開発するための SDK です。
URL: http://code.google.com/intl/ja/appengine/バージョン : 1.4.2■更新情報• 1.4.2 では、JDK でデータベース・インデックスのバキュームが行えるようになったり、XMPP API が更新されたりと、いリリース情報28

G*Magazine vol.1➡ Contents Index

くつかのバグフィックスと改良が行われています。
• 1.4.2 リリースノート : http://code.google.com/p/
googleappengine/wiki/SdkForJavaReleaseNotes

GPars
GPars は、Groovy に直感的で安全な並行処理を提供するシステム
です。
URL: http://gpars.codehaus.org/
バージョン : 0.11GA■更新情報• 0.11GA では、Actor のスピードアップや Memoize( メモ化 )など、いくつかのバグフィックスと改良および新機能の追加が行われています。
• 0.11GA リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=12030&version=16391

Groovy++Groovy++ は、Groovy 言語に対して静的な機能を拡張します。
URL: http://code.google.com/p/groovypptest/
バージョン : 0.4.155■更新情報• 0.4.155 では、いくつかの重要なバグフィックスが行われています。
• 0.4.155 リリースコメント : http://groups.google.
com/group/groovyplusplus/browse_thread/thread/9ac29082ab33b0d9?pli=1

Spock
Spock は、Java や Groovy 用のテストと仕様のためのフレームワー
クです。
URL: http://code.google.com/p/spock/バージョン : 0.5■更新情報• 0.5 では、Hamcrest ライブラリのサポートやビルトイン拡張の追加など、いくつかのバグフィックスと改良および新機能の追加が行われています。
• 0.5 リリースコメント : http://groups.google.com/group/
spockframework/browse_thread/thread/6f84881e99d83531

GroovyServ
GroovyServ は、Groovy 処理系をサーバとして動作させることでgroovy コマンドの起動を見た目上高速化するものです。
URL: http://kobo.github.com/groovyserv/
バージョン : 0.5■更新情報• 0.5 では、起動オプションの追加など、いくつかのバグフィッ
クスと改良および新機能の追加が行われています。
• 0.5 チェンジログ : http://kobo.github.com/groovyserv/
changelog.html#0.5

Geb
Geb は、Groovy を使用した Web ブラウザを自動化する仕組みです。
URL: http://geb.codehaus.org/
バージョン : 0.5.1■更新情報• 0.5.1 では、バグフィックスが行われています。
• 0.5.1 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=12101&version=17012

リリース情報29

G* Magazine vol.1 2011.02
http://www.jggug.org

発行人：日本 Grails/Groovy ユーザーグループ
編集長：川原正隆
編集：G* Magazine 編集委員（杉浦孝博、奥清隆）
デザイン：㈱ニューキャスト
表紙：川原正隆
編集協力：JGGUG 運営委員会
Mail：info@jggug.org© 2011 JGGUG 本誌に掲載されている写真、イラストレーション、および記事の無断転載、使用を禁止します。

Reproduction of any materials appearing
in this magazine is forbidden without priorwritten consent of the publisher.

Publisher：Japan Grails/Groovy User Group
Editor in Chief：Masataka Kawahara
Editors：G* Magazine Editors Team
(Takahiro Sugiura, Kiyotaka Oku)
Design：NEWCAST inc.
CoverDesign：Masataka Kawahara
Cooperation：JGGUG Steering Committee
Mail：info@jggug.org