vol.5

Magazine

Japan Grails/Groovy User GroupContents
Series 07

JGGUG 合宿 2011 企画アプリ

GDK48 投票アプリの作り方（後編）………… 4
Series 08

GroovyFX で遊ぼう（第 2 回）… ……………… 8
Series 04

Geb ではじめる Web テスト〜新機能活用編〜……………………………………… 14
Series 05

Grails Plugin 探訪〜第 6 回 Build Test Data プラグイン〜… …………… 19
JGGUG ４コマ漫画「ぐるーびーたん」第 5 話… …… 25
Information

リリース情報…………………………………………… 26

G*Magazine vol.5

JGGUG合宿2011企画アプリ

GDK48 投票アプリの作り方（後編）
series07

奥 清隆（おく きよたか）

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

前編から少し時間が経ちましたが、今回も後編ということで

JGGUG 合宿 2011 で作成した GDK48 投票アプリの作り方を紹介していきます。今回は、Twitter 連携と投票の仕組みについてです。

Twitter との連携
前回は Twitter からハッシュタグ検索してツイートを拾ってくる処理を実装しましたが、今回は Twitter Authentication プラ

グインを使って認証できるようにします。このプラグインは、
Spring Security Core プラグインの認証に Twitter 認証を利用できるプラグインです。Twitter 認証をアプリケーションで実装することを考えると大変そうに思えますが、このプラグインを使うと簡単に Twitter 認証をアプリケーションに組み込むことができます。次のような手順で Twitter 認証を実装します。

4

GDK48 投票アプリの作り方（後編）

1. Twitter 側にアプリケーションを登録
2. プラグインのインストール＆初期化
3. Twitter 連携ボタンの設置
Twitter やプラグインの設定のみで、ほとんどコードを書く必

要はありません。それではやってみましょう。

■Twitter アプリケーションの登録

アプリケーション申請画面にアクセスして Twitter にアプリ

ケーションを登録します。

https://dev.twitter.com/apps/new

G*Magazine vol.5
Callback URL は、Web アプリケーションの場合に入力する必要

次の内容を入力しましょう。
Name

アプリケーション名

Description

アプリケーションの説明

Websiteアプリケーションの Web サイト

Callback URL

Twitter 認証後にコールバックする URLがありますが、Twitter Authentication が実行時にパラメータとして URL を渡してくれるので、適当な URL で構いません。登録が完了すると Consumer Key と Consumer Secret が発行されます。
後ほど使うのでコピーしておきましょう。

■プラグインのインストール■Twitter 連携ボタンの設置

グインと Twitter Authentication プラグインが必要です。まずは、ンを View に追加します。最低限必要なのは CSS と認証用ボタン

Grails で Twitter 認証するためには、Spring Security Core プラ

Spring Security Core プラグインをインストールしましょう。
$ grails install-plugin spring-security-core

次に、s2-quickstart コマンドを使って必要なドメインの生成とプラグインの設定をします。

$ grails s2-quickstart gdk48 User Role
これで Spring Security Core プラグインがインストールできました。それでは Twitter Authentication のインストールと設定をしていきましょう。

$ grails install-plugin spring-security-twitter

Twitter の認証を使ってアプリケーションにログインするボタのタグだけです。
• CSS<link rel="stylesheet" href="${resource(dir:'css',
ﬁle:'twitter-auth.css')}" />• 認証用ボタンのタグ<twitterAuth:button/>
今 回 は ど の 画 面 か ら で も ロ グ イ ン で き る よ う に grails-app/views/layouts/main.gsp を次のようにします。

s2-init-twitter コマンドを使って、Twitter 連携の設定をします。
$ grails s2-init-twitter
このコマンドを実行すると次の入力を求められます。
• Twitter API Key• Twitter API Consumer Key• Twitter API Consumer Secret
Consumer Key と Consumer Secret は 登 録 し た Twitter ア プ リ

ケーションの値をコピペしましょう。Twitter API Key は Twitter

Authentication プラグイン独自の設定項目ですので任意の値を設定しておきましょう。今回の投票アプリでは「gdk48」としておきました。

GDK48 投票アプリの作り方（後編）5

G*Magazine vol.5<!DOCTYPE html><html><head><title><g:layoutTitle default="Grails" /></title><link rel="stylesheet" href="${resource(dir:'css',ﬁle:'main.css')}" /><link rel="shortcut icon" href="${resource(dir:'images',ﬁle:'favicon.ico')}" type="image/x-icon" /><link rel="stylesheet" href="${resource(dir:'css',ﬁle:'twitter-auth.css')}" /><g:layoutHead /><g:javascript library="application" /></head><body><sec:ifNotLoggedIn><twitterAuth:button/></sec:ifNotLoggedIn><sec:ifLoggedIn>
Logged in as <sec:loggedInUserInfo ﬁeld="username"/></sec:ifLoggedIn><g:layoutBody /></body></html>
これで次のようなボタンが表示されます。試しにボタンをク

このドメインは Gist と投票者でユニークになります。つまり、

リックし、Twitter 認証できれば成功です。初めて Twitter 連携を

投票は同じ Gist に対して 1 人 1 票しか投票できないものとします。

簡単に実装できました。

しまうのは個人的にどうかと思いますので GDK48 の総選挙はこ実装しようとすると、難しそうなイメージがありますが、とても某 48 の総選挙とは仕様が異なりますが、何票でも投票できての仕様で行きたいと思います。

それでは、このドメインを使って投票できるように、
コントロー

投票の実装
Twitter でログインできるようになったので、投票機能を実装

していきましょう。まずは投票を表すドメインクラスを作成します。

▼投票ドメインクラス
package gdk48
class Vote {Gist gist
User voter
static constraints = {gist nullable:false, unique:'voter'
voter nullable:false}}

6

GDK48 投票アプリの作り方（後編）

ラと画面を実装します。

画面の方は前回作っていた list.gsp の内容を変更し、Gist ごとにボタンを設置します。ボタンには現在の獲得票数も表示して、投票と取消しを切り替えられるようにします。次のように変更します。

G*Magazine vol.5<div class="gist"><div><sec:ifLoggedIn><buttononclick="${remoteFunction(
controller:'vote', action:'vote',

投 票 と 投 票 の 取 消 し は Ajax で 処 理 さ れ ま す が、 こ こ で はJavaScript は 1 行も書かずに実装できました。ポイントは投票ボ
タンの onclick 属性に使用している remoteFunction です。

remoteFunction を使用した個所が次のように jQuery を使った

Ajax に展開されます。
jQuery.ajax({

params:[gistNo:gist.gistNo],

type: 'POST',

update:'span_' + gist.gistNo)}">data: {'gistNo': '1261979'},<span id="span_${gist.gistNo}">${gist.voted ? ' 取消 ' : ' 投票 '}url: '/gdk48/vote/vote',
success: function(data,textStatus){
jQuery('#span_1261979').html(data);(${gist.votedCount})</span>},</button>error: function(XMLHttpRequest,</sec:ifLoggedIn>

textStatus, errorThrown) {}</div>});"<div><script src="https://gist.github.com/${gist.
gistNo}.js"></script></div>

remoteFunction で指定したコントローラのアクションにパラメータを付けて POST し、指定した ID をもつ HTML 要素をレスポ</div>

ンスで上書きしてくれます。remoteFunction には他にも指定で投票と取消しは Ajax で出来るようにしてみました。このボタ

照してください。

ンをクリックしたときに呼び出されるコントローラは次のようになります。

きるオプションがいくつかあるので、詳しくはドキュメントを参http://grails.org/doc/latest/ref/Tags/remoteFunction.html■最後にpackage gdk48

さて、前後編と 2 回に分けて GDK48 投票アプリの作り方を紹class VoteController {def springSecurityService

介しました。去年の合宿 0 日目に急遽作ることになり、寝る時間を削って作っていたのが少し懐かしいですが、そろそろ今年も合宿の季節が近づいてきましたね。年を重ねる毎に 1 年が短くなってきているのをひしひしと感じています。JGGUG 合宿 2012 はま

だ未定ですが、今年はゆっくりと温泉につかれるようにしたいと

def vote = {def gist = Gist.ﬁndByGistNo(params.long('gistNo'))

思います。

if (gist) {def vote = Vote.ﬁndByVoterAndGist(
springSecurityService.currentUser, gist)if (vote) {vote.delete(ﬂush:true)

render text:" 投票 (${Vote.countByGist(gist)})"} else {new Vote(
voter:springSecurityService.currentUser,
gist:gist).save(ﬂush:true)

render text:" 取消 (${Vote.countByGist(gist)})"}} else {render status:404}}}

GDK48 投票アプリの作り方（後編）7

G*Magazine vol.5

GroovyFX で遊ぼう！（第 2 回）
series08

関谷 和愛（せきや かずちか）

Groovy、Java、Apple 製品を愛するおっさんエンジニア。日本 Grails/Groovy ユーザーグループ運営委員長。
共著『プログラミング GROOVY』、共訳『Groovy イン・アクション』

前回の導入編では、JavaFX の概要、GroovyFX の入手やビルド方法、そして簡単なサンプルコードを使って GroovyFX の特徴や、シーングラフ構築の基本を紹介しました。今回は、GroovyFX の
もう一つの主要機能であるタイムライン構築を含む、アニメー
ションの基本について説明したいと思います。

そ の 前 に、 前 回 か ら ほ ぼ 半 年 が た っ て お り、GroovyFX とJavaFX にもいくつか大きなアップデートがありましたので、本稿の前半ではまずそれらについてまとめておきます。

JavaFX/GroovyFX アップデート■JavaFX 2.1リリース！

JavaFX の新バージョン、2.1 の正式版がリリースされました。

なんと言っても重要なのは、このバージョンから Mac OS X が正式サポートされたことです。G* 界隈には Mac ユーザが多いので、これは非常に大きな一歩と言えるでしょう。それ以外にも以下の■GroovyFX 正式リリース！

JavaFX の進化にあわせ、GroovyFX もプレビュー段階を終え、ついに正式リリースとなりました！

新しい Web サイトが用意され、ソースは svn から github 上に移され、jar ファイルでのダウンロードも可能になりました（もう自分でビルドする必要はありません）。何より大きいのはライブラリが maven の central リポジトリに登録されたことです。これにより、@Grab で GroovyFX を利用することができるようになりました（後述のサンプルソースを参照）。また、Gradle を使う
場合、build.gradle で次のように依存関係を記述できます：// build.gradle ( 抜粋 )repositories { mavenCentral() }dependencies {groovy 'org.codehaus.groovy:groovy-all:1.8.6'

ような大きな機能追加がありました：

compile 'org.codehaus.groovyfx:groovyfx:0.2'
compile ﬁles(<JavaFX の jfxrt.jar へのパス >)• H.264+AAC を 格 納 し た MPEG-4 コ ン テ ナ の 再 生 を サ ポ ー ト}• WebView/WebEngine で JavaScript からの Java の呼び出しをサGroovyFX のバージョン 0.1 は JavaFX 2.0 に、0.2 は JavaFX 2.1 に（これまでは VP6+MP3/FLV だけ）
ポート（これで双方向に！）対応しています。ベータ公開中の JavaFX 2.2 には GroovyFX 0.3 がComboBox、StackedAreaChart、StackedBarChart

2.1/GroovyFX 0.2 を使っています。

• UI コントロールやチャートの追加：• Mac OS 風システムメニューバー対応：
MenuBar.setUseSystemMenuBar(true)• OS 標準の DirectoryChooser• シーングラフをビジュアルに構築するツール、Scene Builderのベータ版リリース (Win/Mac)

Windows でも Mac でも最新の JDK7 に JavaFX 2.1 がバンドルされるようになり、インストールがより簡単になっています。また、次のバージョンである 2.2 のベータ版も公開されました。

8

GroovyFX で遊ぼう！（第２回導入編）

対応予定です (SNAPSHOT 利用可 )。本稿のサンプルでは JavaFX

な お、GroovyFX 0.2 で は、 一 つ 大 き な 変 更 が あ り ま し た。

GroovyFX の中核である SceneGraphBuilder は、0.2 からは明示的に生成する必要はなくなりました。start メソッドに渡すクロー

ジャ内では、SceneGraphBuilder が自動的に生成され、クロージャの delegate に設定されます。これによって、クロージャ内のメ

ソッド呼び出しはこの SceneGraphBuilder オブジェクトに対して行われます。具体的なコードは後半のサンプルを参照してください。

G*Magazine vol.5

アニメーション入門

トランジションを定義するには、シーングラフ構築の記述で、

さて、本題のアニメーションに進みましょう。JavaFX でのアニメーションには、トランジション (javafx.animation.Transition) と、
タイムライン (javafx.animation.Timeline) を使ったアニメーショ

対象ノードの子ノードとして（後続のクロージャ内に）適用する
トランジションを記述します。下記の例では、rectangle ノード
を 3 秒間で 360 度回転させる rotateTransition を定義しています：

ンの２種類があります。どちらも javafx.animation.Animation イ

rectangle(x: 100, y: 100, width: 50, height: 50) {す：}

ンタフェースを継承していて、以下のような共通の特性がありまtransition = rotateTransition(3.s, from: 0, to: 360)transition.play()• play()/stop() などのメソッドで再生や停止を制御する• onFinished にクロージャを渡して終了時の処理を指定できる• 自動反転のオン・オフ (autoReverse)、繰り返し回数 (cycleCount)などのプロパティを持つ

トランジションは種類によらず、最初の引数には必ず持続時間(javafx.util.Duration) を指定します。GroovyFX では、Duration を指定する場合、500.ms、3.s、3.min、1.h といったリテラル風表現が可能です。

では、トランジションとタイムラインアニメーションのそれぞれについて、使い方や具体例をみていきます。

実際にこのトランジションを動作させるときは、play() メソッ

ドを呼びます。

■トランジション

トランジションは特定のシーングラフノードに適用する、あらかじめ用意された視覚効果のことです。
名前

トランジションには次のようなものがあります：
効果

主な引数

備考

fadeTransition

フェードイン／アウト

from/to で透明度指定 (0: 透明〜
1: 不透明 )rotateTransition

回転

from/to で角度指定 (0 〜 360 度 )scaleTransition

拡大／縮小

from/to で倍率指定

pathTransition

移動（経路指定）

path で経路 (Shape) 指定

translateTransition

移動（終点 / 差分指定）

fromX/Y/Z（始点）から toX/Y/
Z（終点）または byX/Y/Z（差分）fillTransition

塗りつぶし色の変更

from/to で色指定

Shape ノードにのみ適用可能

strokeTransition

枠線色の変更from/to で色指定

Shape ノードにのみ適用可能

pauseTransition

休止なし

SequentialTransition の中で間をとるためだけに存在複数のトランジションを合成することもできます。SequentialTransition は複数のトランジションを順番に実行し、ParallelTransition

は複数のトランジションを同時に実行します（回転しながらフェードアウトするなど）。

●トランジションの例：怒れる鳥たち

具体的なトランジションの例として、某人気ゲームのオープニングをイメージしたアニメーションを作ってみました。

GroovyFX で遊ぼう！（第２回導入編）

9

G*Magazine vol.5@Grab('org.codehaus.groovyfx:groovyfx:0.2')
import static groovyx.javafx.GroovyFX.start
start {
stage(visible: true) {scene(width: 640, height: 480, ﬁll: lightskyblue) {// 緑の鳥：回転しながら path に沿って飛ぶ（周期 4 秒）
imageView {image("ﬁle:green_bird.png", width: 80, height: 80)
greenAnim = parallelTransition {pathTransition(4.s,path: quadCurve(startX: 0, startY: 200,
controlX: 320, controlY: 0,
endX: 640, endY: 200),
interpolator: linear, cycleCount: indeﬁnite)rotateTransition(2.s, from: 0, to: 360,
interpolator: linear, cycleCount: indeﬁnite)}}// 豚：拡大・縮小を繰り返しながら path に沿って飛ぶ（周期 3 秒）
imageView {image("ﬁle:pig.png", width: 120, height: 120)
pigAnim = parallelTransition {pathTransition(3.s,path: quadCurve(startX: 0, startY: 300,
controlX: 320, controlY: 100,endX: 640, endY: 300),
interpolator: linear, cycleCount: indeﬁnite)scaleTransition(1.s, from: 1.0, to: 0.5,
autoReverse: true, cycleCount: indeﬁnite)}}// 赤い鳥：path に沿って飛ぶ（周期 2 秒）
imageView {image("ﬁle:red_bird.png", width: 160, height: 160)
redAnim = pathTransition(2.s,path: quadCurve(startX: 0, startY: 400,
controlX: 320, controlY: 200,
endX: 640, endY: 400),
interpolator: linear, cycleCount: indeﬁnite)}}}// 各トランジションを再生
redAnim.play()
pigAnim.play()greenAnim.play()}

10 GroovyFX で遊ぼう！（第２回導入編）

G*Magazine vol.5（イメージファイルはこちらから入手してください :https://dl.dropbox.com/u/132573/birds_images.zip）

実行は簡単です（@Grab を使っているので GroovyFX をインストールしておく必要すらありません）：

groovy -classpath <JavaFX の jfxrt.jar へのパス >birdsAnim.groovy
この例では、３つの imageView ノードを用意し、それぞれを別々の周期の pathTransition で動かしています。１つのノードに は さ ら に rotateTransition を か け て 回 転 さ せ、 別 の １ つ に は

scaleTransition を適用して拡大・縮小を繰り返させています。トランジションの複合には parallelTransition を使っています。

コード中、cycleCount プロパティに指定している indefinite は

無限回を表す疑似定数です。interpolator はアニメーションの加減速を指定するプロパティです。トランジションの場合、デフォ■タイムライン

タイムラインは、時間軸にそってオブジェクトのプロパティの変化を定義するものです。タイムラインはアニメーション以外にも利用可能ですが、オブジェクトの視覚的なプロパティを変化させればアニメーションを実現できます。オブジェクトの位置を変化させればオブジェクトは移動し、透明度を変化させればフェー

ドイン・アウトし、大きさを変化させれば拡大・縮小する、といった具合です。

タイムラインは、
複数のオブジェクト／プロパティを操ったり、独自のタイミング制御を定義したりできるので、トランジションに比べ、より汎用的なアニメーション手法と言えます。また、トランジションや別のタイムラインと複合させて、より複雑なアニ
メーションを実現することも可能です。

タイムラインは、一連のキーフレームで定義されます。キーフ

ルト値は ease_both（ゆっくりスタートして加速してゆき、終了

レームとは、ある時刻におけるオブジェクトの状態（プロパティ

linear に設定して加減速のない一定なテンポに設定しています。

ブジェクトの状態は自動的に補完され、連続した変化として再生に向けてまた減速する）ですが、このサンプルでは多くの箇所で

なお、この例は GroovyFX 0.2 で書いているので、start メソッ

ドのクロージャの冒頭で、SceneGraphBuilder の生成をすることなく、いきなり stage 以下のシーングラフの構築を行っていることにも注意してください。

値）を定義したものです。キーフレームとキーフレームの間のオされます。

次の例では、まず circle ノードを作成し、キーフレームで５秒後の centerX と fill プロパティ値を定義することで、タイムライン
アニメーションを作成しています。circle は５秒かけて中心座標
が 100 から 300 になるよう水平に移動しつつ、黄色から赤に段階的に色が変わっていきます。

GroovyFX で遊ぼう！（第２回導入編） 11

G*Magazine vol.5

circle = circle(
centerX: 100, centerY: 200, radius: 50,
ﬁll: yellow)
timeline = timeline {at (5.s) {change (circle, 'centerX') {to 300; tween ease_both}change (circle, 'ﬁll') { to red }}}timeline.play()
タイムラインを定義するとき、GroovyFX 0.1 までは明示的にTimelineBuilder を生成する必要がありましたが、0.2 からは（start
メソッドのクロージャ内であれば）timeline ノードをいきなり記述することができます。

timeline ノードは子ノードとして１個以上の at ノードを持ち、また autoReverse、cycleCount、onFinished などの引数をとることもできます。

@Grab('org.codehaus.groovyfx:groovyfx:0.2')
import static groovyx.javafx.GroovyFX.startat ノードはキーフレームを定義し、最初の引数には必ず時刻を指定します。onFinished クロージャで任意の処理を指定すること

start {

も可能です。at は任意個の change ノードを持つことができます。

stage(visible: true) {scene(width: 400, height: 400, ﬁll: black) {change ノードでは、どのオブジェクトの、どのプロパティが、

circle(centerX: 200, centerY: 200, radius:

どんな値になるのかを定義します。クロージャ内には１個の to110, ﬁll: yellow) {こともでき、これはプロパティ変化の interpolator として働きま50)

ノード（必須）に加え、オプションで tween ノードを指定する

effect dropShadow(color: white, radius:

す。タイムラインでの tween のデフォルトは linear です（トラン}ジションとは異なるので注意）。

moon = circle(centerX: 400, centerY: 0,
radius: 100, ﬁll: black)

タイムラインを実際に動作させるときはトランジション同様、}

play() メソッドを呼ぶ必要があります。

}●タイムラインの例：金環日食

eclipse = timeline {at (60.s) {ごく簡単なタイムラインアニメーションの例として、金環日食

change (moon, 'centerX') { to 0 }シミュレータを作ってみました。

change (moon, 'centerY') { to 400 }}}eclipse.play()}

この例では、キーフレームとして 60 秒後の moon オブジェク

ト（月を表す黒い円）の位置を定義することにより、月をゆっく
りと動かしています。
「どう動かすか」ということはまったくプ

ログラムしていませんが、月の初期位置とキーフレーム定義から、JavaFX のランタイムが中間状態を補完し、自動的にアニメーショ
ンを作り出しているのです。

12 GroovyFX で遊ぼう！（第２回導入編）

G*Magazine vol.5

コラム - GroovyFxPad
G* な GUI アプリケーションフレームワーク、Griffon も先日つ

いに 1.0 がリリースされました！

このリリースには、GroovyFxPad という面白いサンプルアプリが同梱されています。左側のペインに GroovyFX なコード（シーングラフノードを返すように書く）を入力して実行すると、右側のペインに実行結果が即座に表示されます。シーングラフやアニ
メーションのパラメータをいろいろ変えながら出力結果をチェックできるので試行錯誤や勉強にはなかなか便利です。ぜひダウンロードして試してみてください：

http://griffon.codehaus.org/Download

まとめ
今 回 は JavaFX/GroovyFX の ア ッ プ デ ー ト 情 報 と、 ア ニ メ ーションの基本を説明しました。より複雑なアニメーションやGroovyFxPad などについては下記リンクのブログ記事（およびそのリンク先）なども参考にしてください。

これで GroovyFX の主要機能であるシーングラフとタイムライ

ン構築はひとめぐりしたので、今後は個々の機能についてより深く掘り下げるか、あるいはもう少し本格的なアプリケーションに取り組んでみようと思います。感想やリクエストなどがあればTwitter: @kazuchika までぜひお知らせください。

■リンク• JavaFX http://www.oracle.com/technetwork/java/javafx/overview/• GroovyFX http://groovyfx.org/• サンプルコード（怒れる鳥たち）https://gist.github.com/2963721• サンプルコード（金環日食）https://gist.github.com/2963743• GroovyFX 初の正式リリース（翻訳）- Groovy ラボ
http://d.hatena.ne.jp/ksky/20120422/p1• 複雑なアニメーション（GroovyFX 版）- Groovy ラボ
http://d.hatena.ne.jp/ksky/20120613/p1

GroovyFX で遊ぼう！（第２回導入編） 13

G*Magazine vol.5

GebではじめるWebテスト〜第３回 〜新機能活用編〜
series04

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

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

G* な皆さん、こんにちは。前回の Geb0.6 編からだいぶ時間が経ったこともあって、Geb はこの間に 4 度のバージョンアップを重ね、新たな API や振る舞いが変わるような変更が多く取り込まれました。そこで今回は新機能活用編として、バージョン 0.6 から今年 4 月にリリースされたバージョン 0.7.0 までに追加された主要な新機能を中心に解説したいと思います。

Geb 0.6.1 - 0.7.0 までの新機能・変更点
0.6.1 以降からは依存するライブラリのバージョンアップに伴う対応から、様々な新機能の追加、既存の振る舞いの見直しなど多くの変更が入りました。Geb のマニュアルの変更履歴には、全部で 31 もの新機能と重要な変更が記載されていますが、その中から主要なものを以下にまとめました。
カテゴリ
依存ライブラリ

概要
Selenium 2.9.0 に対応
Spock 0.6 に対応
select 要素を使用する場合は、selenium-support.jar が必須

新機能

暗黙のアサーション
マウスやキーボード操作のインタラクション支援
繰り返しのコンテンツを扱うモジュールリスト
ウィンドウフレームへの対応
複数ウィンドウへの対応

新機能

ブラウザのキャッシュ機構
waitFor() のためのカスタムタイムアウトメッセージ
Content DSL での別名パラメータ指定

振る舞い変更Navigator#classes() の戻り値が Set からアルファベット順のソートが保証された List になった
Page#convertToPath() は必要に応じて接頭辞のスラッシュを追加するようになった
チェックボックスがチェックされていない状態は null の替わりに false を返すようになった

これらの中から、使用頻度が高いと思われるウィンドウ関連の 2 機能、モジュールリストと 0.7.0 から導入された暗黙のアサーショ

ンについて見ていきます。

■ウィンドウフレーム

一般的な Web のデザインではウィンドウをフレームで分割するような構造のものは少なくなってきましたが、エンタープライズ系のシステムではまだまだフレーム分割を行っている画面もあるかと思います。Geb 0.6.2 以

降ではフレームを扱うことができるようにな

り、フレーム内のコンテンツへのアクセスが可能になりました。

次のサンプル画面では、分割された上部フ

レームの「update action」ボタンを押下すると、下部フレームのテキストが約 5 秒後に更新されます。

14 Geb ではじめる Web テスト〜新機能活用編〜

G*Magazine vol.5
ここでのボタン押下からテキスト更新までの動作をテストしてみましょう。トップ画面とそれに対する Page クラスのソース
コードは次のようになります。
<html>

フレーム内の画面を扱う場合は、withFrame() を使用します。

まず、when: ブロックで header を引数にして上部フレームのボタンを押下させます。そして、次に then: ブロックで下部フレームの検証を行います。

しかし、このサンプルでは更新タイミングを 5 秒後に遅らせて<head>

いるため、そのまま assert してしまうと即時検証され、テストが</head>

失敗してしまいます。このような場合は waitFor() を使用して更<frameset rows="20%,*"><frame name="headerFrame" id="header"
src="header.html"></frame><frame name="mainFrame" id="main"src="main.html"></frame></frameset>

新されるまで待機させる必要があります。Geb のデフォルトの

待機時間は 5 秒となっていますが、今回の更新タイミングも 5 秒
後のため、場合によってはタイムアウトしてしまうこともあります。そのため、ここでは待機時間を 6 秒として設定しています。

ち な み に、withFrame() {…} == null と し て い る の は、</html>withFrame() の戻り値（ null となる）を評価しないと、テスト失敗となってしまうためです。これは Spock のバグらしく※、一時class NewFunctionsPage extends Page {static url ='http://localhost:8080/hello/samples/frameTop.html'的な対応として、このような実装としています。
▼ 実行結果static content = {header { $('#header') }main { $('#main') }}また、わざと待機時間を短くしてテストを実行してみると、以}下のように WaitTimeoutException がスローされ、waitFor() の引

Spock を利用したテストコードは以下のようになります。

数に設定したカスタムメッセージが出力されます。

class NewFunctionsSpec extends GebReportingSpec {def "[update action] ボタンを押すと、5秒後に下フレームが更新される。"() {given:

to NewFunctionsPage
when:
withFrame(header) {$('#updateActionButton').click() }then:
withFrame(main) {assert waitFor(

message:' タイムアウト！ ', 6){ $('div') }.text() == 'update text!'} == null}}※ Geb の 同 様 の テ ス ト コ ー ド に「can't put this in an expect
block, some spock bug」とコメントがありました。

Geb ではじめる Web テスト〜新機能活用編〜

15

G*Magazine vol.5■複数ウィンドウ▼実行結果

別ウィンドウやタブに参照情報を表示させるような場面は、よくあるケースだと思いますが、Geb 0.6.2 から複数ウィンドウに対する制御も行えるようになりました。

先ほどのサンプル画面の上部フレームの「window action」ボ

タンを押下すると子画面が、「tab window action」ボタンを押下するとタブ画面が表示されます。これらの別画面に対するテスト
コードは以下のようになります。

■モジュールリスト

Web での検索結果や確認画面での表は、概ね同じ構成の繰り

def "[window action] ボタンを押すと、子画面が表示される。"() {返しになります。そのような内容を含んだ画面をテストする際の仕組みとしてモジュールリスト機能が Geb 0.6.2 から導入され、さらに 0.7.0 からモジュールリストにインデックスや範囲を指定して操作できるようになりました。

given:
to NewFunctionsPage

次の単純なテーブル要素の画面をモジュールリストを使用してテストしてみましょう。

when:
withFrame(header) { $('#windowActionButton').click() }then:
withWindow('childWindow') {assert $('title').text() == 'child window'} == null}

def "[tab window action] ボタンを押すと、タブ画面が表示される。"() {given:

to NewFunctionsPage
expect:withNewWindow({ withFrame(header) {$('#tabWindowActionButton').click()} }) {
assert $('title').text() == 'tab window'} == null}
別 ウ ィ ン ド ウ を 扱 う 際 に は、withWindow() かwithNewWindow() を 使 用 し ま す。 子 画 面 の 検 証 に は ウ ィ ン

ドウ名を指定して withWindow() を呼び、クロージャ内で検証をします。タブ画面ではウィンドウ名を指定していないため、画面とそれに対する Page クラスは以下のようになります。
<html><head><title>G* ProductList</title></head><body><div>G* なプロダクト </div><table border="1"><tr><th>Product</th><th>Current Version</th></tr><tr><td>Groovy</td><td>1.8.6</td></tr><tr><td>Grails</td><td>2.0.4</td></tr><tr><td>Griffon</td><td>1.0.0</td></tr><tr><td>Gradle</td><td>1.0</td></tr><tr><td>Spock</td><td>0.6</td></tr><tr><td>Geb</td><td>0.7.0</td></tr>

withNewWindow() を使用しています。withNewWindow() はウィ</table>レームのボタン操作を記述しています。

</html>

ンドウを開く処理を行うクロージャを引数とするため、上部フ16 Geb ではじめる Web テスト〜新機能活用編〜</body>G*Magazine vol.5

class RepeatingContentPage extends Page {class RepeatingContentPage070 extends Page {static url =static url ='http://localhost:8080/hello/samples/repeating.html''http://localhost:8080/hello/samples/repeating.html'

static content = {static content = {gProducts { moduleList TableContent,

gProducts { index -> moduleList TableContent,$('table tr').tail() }$('table tr').tail(), index }

}

}

}

}

class TableContent extends Module {def " テーブルの特定範囲の内容だけを検証する。"() {when:static content = {to RepeatingContentPage070

cell { $('td', it) }productName { cell(0).text() }then:currentVersion { cell(1).text() }gProducts(4..5)*.productName == ['Spock', 'Geb']}

gProducts(4..5)*.currentVersion == ['0.6', '0.7.0']}}

こ こ で の ポ イ ン ト は、RepeatingContentPage ク ラ ス の

gProducts 内で $('table tr').tail() としているところです。これにより、テーブルのヘッダー行を除いてリスト化しています。

▼実行結果

テストコードは以下のようになります。
@Unrolldef " テーブルの内容を検証する。"() {when:
to RepeatingContentPagethen:gProducts[index].productName == productName
gProducts[index].currentVersion == currentVersion
where:
index | productName | currentVersion
0| 'Groovy'| '1.8.6'

1| 'Grails'| '2.0.4'

2| 'Griffon'| '1.0.0'

3| 'Gradle'| '1.0'

4| 'Spock'| '0.6'

5| 'Geb'| '0.7.0'}
ここでは Spock ではお馴染みのデータドリブンテストを利用して全ての内容について検証しています。範囲指定をしたテストは次のようになります。

Geb ではじめる Web テスト〜新機能活用編〜

17

G*Magazine vol.5

G*Magazine vol.5■暗黙のアサーション▼バージョン 0.7.0 での実行結果

0.7.0 から導入された機能の内、注目すべきなのが、暗黙のアサーション（implicit assertions）です。これは特定のブロックのコードを自動的にアサーションするように置き換える仕組みです。現時点では waiting 式と at 式に対して使用されています。

具体的にどのような動きをするのかを 2 つのバージョンの at式で比較してみましょう。以下のコードは assert at(HelloPage)の行で失敗するテストコードです。

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')}}}バージョン 0.6.3 ではテストコードの assert で判定されるため、ただ false としか出力されませんが、暗黙のアサーションが行われるバージョン 0.7.0 では、HelloPage クラスの at 式の中でassert title == 'hello' が実行されるため、具体的な値が出力されるようになります。さらに、テストコード内で明示的に assert

at() と記述する必要もなくなるため、テストコードも読み易くなります。この暗黙のアサーションは AST 変換によって実装されており、開発者は全く意識することなく、恩恵を享受することが
できます。

まとめ
@Test
void helloJGGUG() {to HelloPage
assert at(HelloPage)
username = 'JGGUG'
greetButton.click()assert at(GreetingPage)
assert h1Text == 'Hello, JGGUG!'}
これを 0.6.3 と 0.7.0 で実行すると、次のようになります。
▼バージョン 0.6.3 での実行結果

18 Geb ではじめる Web テスト〜新機能活用編〜

以上、実用的な新機能を中心にお伝えしましたが、如何でしたでしょうか？ウィンドウ機能の強化により、フレーム構造の画面や子画面を出すような場合にも対応することができるようになりましたし、waiting 式と併用することで、テスト実行時にも実際の画面遷移を想定した動作をさせることが可能です。また、モジュールリストや暗黙のアサーションは、テストコードをシンプ
ルにし、失敗時の結果も分かり易くなりました。

さらに高機能で簡潔になった Geb に興味を持たれた方は、是非とも試してみてください。

■リンク• Geb マニュアル

http://www.gebish.org/manual/current/

G*Magazine vol.5

Grails Plugin 探訪
第6回~ Build Test Data プラグイン ~URL: http://grails.org/plugin/build-test-data
プラグインのバージョン : 2.0.2対応する Grails のバージョン : 2.0.0 以上

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

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

はじめに今回ご紹介する Grails プラグインは、Build Test Data プラグイ

ンです。

package testdataclass Book {本記事は、次の環境で動作確認をしております。

String title• OS : Mac OS X 10.6.8

int price• Grails : 2.0.4

String isbn13

果を省略しており、実際の出力と異なる場合があります。ご了承static belongsTo = [author: Author]• Java : 1.6.0_31

Date published

なお、コマンドの実行結果については、紙面の都合上、出力結願います。

static constraints = {title(blank: false)

Build Test Data プラグインとはprice(nullable: false)
published(nullable: false)

Build Test Data プラグインは、ドメインクラスの制約から自動

isbn13(blank: false)

的にテストデータを作成するためのプラグインです。ドメインクラスが持つプロパティの制約を解析し、その制約に合う値を持つ}インスタンスを生成します。

}

プラグインのインストール

package testdata

Build Test Data プラグインのインストールは、grails の install-class Author {plugin コマンドで行います。

String ﬁrstName
String lastName$ grails create-app testdata$ cd testdata

static hasMany = [books: Book]$ grails install-plugin build-test-data
static constraints = {ドメインクラスの作成

ﬁrstName(blank: false)
lastName(blank: false)

今回のサンプルのドメインクラスとして、本 (Book) クラスと

著者 (Author) クラスを使用します。

}}
上述のドメインクラスをベースに、必要に応じ変更します。

Grails Plugin 探訪

第 6 回 ~ Build Test Data プラグイン ~19

G*Magazine vol.5

ドメインクラスのインスタンス生成
Build Test Data プラグインをインストールすることで、ドメインクラスに build メソッド、および buildLazy メソッドがインジェ■integration test の場合

integration test でも、そのまま build/buildLazy メソッドが使用できます。

クションされます。

package testdata■grails console コマンドの場合

import static org.junit.Assert.*

grails console コマンドでは、そのまま build/buildLazy メソッドが使用できます。ドメインクラスのインスタンスを生成、プロ
パティに値を設定し、保存します。

import org.junit.*class BookServiceTests {$ grails console@Before...

void setUp() {import testdata.Author}

def author = Author.build()
println "First Name = '${author.ﬁrstName}'"@Afterprintln "Last Name = '${author.lastName}'"void tearDown() {println "ID = '${author.id}'"}

実行結果は次のとおりです。

@Test
void testSomething() {First Name = 'ﬁrstName'def book = Book.build()

Last Name = 'lastName'dump(book)

ID = '1'}
private dump(book) {println "Title = '${book.title}'"println "Price = '${book.price}'"println "Published = '${book.published}'"println "ISBN13 = '${book.isbn13}'"println "Book's ID = '${book.id}'"
println "First Name = '${book.author.ﬁrstName}'"println "Last Name = '${book.author.lastName}'"println "Author's ID = '${book.author.id}'"}}
実行結果は次のとおりです。
Title = 'title'
Price = '0'
Published = 'Sun Jun 03 02:11:06 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '1'
First Name = 'ﬁrstName'
Last Name = 'lastName'
Author's ID = '1'

20 Grails Plugin 探訪 第 6 回 ~ Build Test Data プラグイン ~G*Magazine vol.5■unit test の場合■プロパティに設定する値を変更したい場合できません。テストクラスに、@Build アノテーションで build/build/buildLazy メソッドにマップ形式で変更したい値を指定しunit test の場合、そのままでは build/buildLazy メソッドが使用

buildLazy メソッドを使用したいドメインクラスを指定します。
複数クラスを対象にする場合、リストで指定します。

インスタンスのプロパティに設定する値を変更したい場合、ます。

def book = Book.build(title: 'Grails Programming',

package testdata

price: 3500)

import grails.test.mixin.*

実行結果は次のとおりです。

import org.junit.*
import grails.buildtestdata.mixin.Build@TestFor(BookController)@Build(Book)
class BookControllerTests {void testSomething() {def book = Book.build()

Title = 'Grails Programming'
Price = '3500'
Published = 'Sun Jun 03 02:57:41 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '1'
First Name = 'ﬁrstName'
Last Name = 'lastName'
Author's ID = '1'

dump(book)}■buildLazy メソッドについて

private dump(book) {println "Title = '${book.title}'"println "Price = '${book.price}'"println "Published = '${book.published}'"build メソッドは実行ごとにドメインクラスのインスタンスを生成しますが、buildLazy メソッドは build/buildLazy メソッドで生成した同じ値を持つインスタンスがあれば、そのインスタンスを再利用します。

println "ISBN13 = '${book.isbn13}'"

void testSomething() {println "Book's ID = '${book.id}'"def book = Book.build(

println "First Name = '${book.author.ﬁrstName}'"title: 'Grails Programming',

println "Last Name = '${book.author.lastName}'"price: 3500,

println "Author's ID = '${book.author.id}'"

author: Author.build()

}

)

}

println '[book]'
dump(book);

実行結果は次のとおりです。

def book2 = Book.build(

Title = 'title'
Price = '0'

title: 'Grails Programming 2',

Published = 'Sun Jun 03 02:11:06 JST 2012'

price: 3600,

ISBN13 = 'isbn13'

author: Author.build()

Book's ID = '1')

First Name = 'ﬁrstName'

println '[book2]'
dump(book2);

Last Name = 'lastName'}

Author's ID = '1'}

Grails Plugin 探訪

第 6 回 ~ Build Test Data プラグイン ~21

G*Magazine vol.5
実行結果は次のとおりです。ID が book と book2 で違うことから、Book と Author のインスタンスが build メソッドの呼び出しごとに生成されるのがわかると思います。
[book]

実行結果は次のとおりです。Book インスタンスの ID が異なる

ため、Book インスタンスは別々に生成され、Author インスタン

スの ID は同じのため、Author インスタンスは再利用されていることがわかります。

Title = 'Grails Programming'[book]

Price = '3500'

Title = 'Grails Programming'

Published = 'Sun Jun 03 03:27:09 JST 2012'

Price = '3500'

ISBN13 = 'isbn13'

Published = 'Sun Jun 03 03:30:34 JST 2012'

Book's ID = '1'

ISBN13 = 'isbn13'

First Name = 'ﬁrstName'

Book's ID = '1'

Last Name = 'lastName'First Name = 'ﬁrstName'

Author's ID = '1'

Last Name = 'lastName'
Author's ID = '1'[book2]
Title = 'Grails Programming 2'[book2]

Price = '3600'

Title = 'Grails Programming 2'

Published = 'Sun Jun 03 03:27:09 JST 2012'

Price = '3600'

ISBN13 = 'isbn13'

Published = 'Sun Jun 03 03:30:34 JST 2012'

Book's ID = '2'

ISBN13 = 'isbn13'

First Name = 'ﬁrstName'

Book's ID = '2'

Last Name = 'lastName'First Name = 'ﬁrstName'

Author's ID = '2'

Last Name = 'lastName'

次に、Book インスタンスは別々に、Author インスタンスを再Author's ID = '1'

利用します。Author の build メソッド呼び出しを buildLazy メソッ
ド呼び出しに変更します。

void testSomething() {def book = Book.buildLazy(title: 'Grails Programming',
price: 3500,
author: Author.buildLazy()■インスタンスを保存したくない場合

build/buildLazy メソッドはインスタンスの保存を行いますが、インスタンスの保存をしたくない場合、buildWithoutSave メソッドを使用します。

void testSomething() {def book = Book.buildWithoutSave()

title: 'Grails Programming',

println '[book]'

price: 3500,

dump(book);author: Author.buildWithoutSave())

def book2 = Book.buildLazy(println '[book]'

title: 'Grails Programming 2',

dump(book);

price: 3600,
author: Author.buildLazy()def book2 = Book.buildLazy()

title: 'Grails Programming 2',

println '[book2]'

price: 3600,

dump(book2);

author: Author.buildLazy()})
println '[book2]'
dump(book2);}

22 Grails Plugin 探訪 第 6 回 ~ Build Test Data プラグイン ~G*Magazine vol.5
実行結果は次のとおりです。book の方の ID が null となっていることで保存されていないことがわかります。

次のとおりです。TestDataConfig.groovy で指定した値がインスタンスに設定されているのがわかります。

[book]

Title = 'Easy Grails Programming'

Title = 'Grails Programming'

Price = '3000'

Price = '3500'

Published = 'Sun Jun 03 10:24:50 JST 2012'

Published = 'Sun Jun 03 03:53:50 JST 2012'

ISBN13 = 'isbn13'

ISBN13 = 'isbn13'

Book's ID = '1'

Book's ID = 'null'First Name = 'Ichiro'First Name = 'ﬁrstName'

Last Name = 'Suzuki'

Last Name = 'lastName'

Author's ID = '1'

Author's ID = 'null'■設定する値を動的に変更したい場合[book2]
Title = 'Grails Programming 2'
Price = '3600'
Published = 'Sun Jun 03 03:53:51 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '1'

設定する値をインスタンスごとに動的に設定したい場合もあると思います。その場合、クロージャを使用することで指定可能です。

testDataConﬁg {sampleData {First Name = 'ﬁrstName''testdata.Author' {Last Name = 'lastName'

ﬁrstName = 'Ichiro'

Author's ID = '1'

lastName = 'Suzuki'}

デフォルト動作の変更'testdata.Book' {def no = 1

引数なしで build/buildLazy メソッドを呼び出した場合、プロ

def delta = 1

パティに設定される値はプロパティ名や Constraints をもとに設

title = { "Easy Grails Programming ${no++}" }定されますが、固定の値を設定したい場合があります。

まず、Config ファイルのテンプレートをインストールします。

次 の コ マ ン ド を 実 行 す る と、grails-app/conf/TestDataConfig.
groovy が作成されます。

$ grails install-build-test-data-conﬁg-template

price = { 3000 + 100 * delta++ }}}}Book クラスのインスタンスを 3 つ生成します。
void testSomething() {testDataConfig/sampleData の中に、ドメインクラスごとにプ

def book1 = Book.build()

ロパティに設定したい値を指定します。

println '[book1]'
dump(book1);

testDataConﬁg {sampleData {def book2 = Book.build()'testdata.Author' {println '[book2]'

ﬁrstName = 'Ichiro'

dump(book2);

lastName = 'Suzuki'}

def book3 = Book.build()'testdata.Book' {println '[book3]'

title = 'Easy Grails Programming'
price = 3000

dump(book3);}}}}
引数を指定していない build メソッドを呼び出した実行結果はGrails Plugin 探訪

第 6 回 ~ Build Test Data プラグイン ~23

G*Magazine vol.5
実行結果は次のとおりです。title, price がインスタンスごとに実行結果は次のとおりです。

[book1]
Title = 'Easy Grails Programming 1'
Price = '3100'
Published = 'Sun Jun 03 10:42:03 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '1'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '1'--Output from testSomething1-[book1]
Title = 'Easy Grails Programming 1'
Price = '3100'
Published = 'Sun Jun 03 11:24:55 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '1'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '1'[book2]
Title = 'Easy Grails Programming 2'
Price = '3200'
Published = 'Sun Jun 03 10:42:03 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '2'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '2'[book2]
Title = 'Easy Grails Programming 2'
Price = '3200'
Published = 'Sun Jun 03 11:24:55 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '2'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '2'[book3]
Title = 'Easy Grails Programming 3'
Price = '3300'
Published = 'Sun Jun 03 10:42:03 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '3'First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '3'--Output from testSomething2-[book1]
Title = 'Easy Grails Programming 3'
Price = '3300'
Published = 'Sun Jun 03 11:24:55 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '1'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '1'

違う値が設定されていることがわかります。

■設定する値をリセットしたい場合

先の設定はインスタンスの生成ごとに値が変わりますので、異なるテストメソッド中でインスタンスを生成した場合、異なる値となります。

void testSomething1() {def book1 = Book.build()
println '[book1]'
dump(book1);
def book2 = Book.build()
println '[book2]'
dump(book2);}
void testSomething2() {def book1 = Book.build()
println '[book1]'
dump(book1);
def book2 = Book.build()
println '[book2]'
dump(book2);}

24 Grails Plugin 探訪 第 6 回 ~ Build Test Data プラグイン ~[book2]
Title = 'Easy Grails Programming 4'
Price = '3400'
Published = 'Sun Jun 03 11:24:55 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '2'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '2'
設定をリセットすることで、プロパティに設定する値を振り直すことができます。例えばテストメソッドごとに値を振り直した
い場合、setUp メソッドで次のコードを実行します。

void setUp() {grails.buildtestdata.TestDataConﬁgurationHolder.reset()}

G*Magazine vol.5--Output from testSomething1-[book1]
Title = 'Easy Grails Programming 1'
Price = '3100'
Published = 'Sun Jun 03 11:26:09 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '1'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '1'[book2]
Title = 'Easy Grails Programming 2'
Price = '3200'
Published = 'Sun Jun 03 11:26:10 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '2'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '2'※現在は「http://docs.oracle.com/」ドメインで日本語 javadoc が復活しています。

--Output from testSomething2-[book1]
Title = 'Easy Grails Programming 1'
Price = '3100'
Published = 'Sun Jun 03 11:26:10 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '1'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '1'[book2]
Title = 'Easy Grails Programming 2'
Price = '3200'
Published = 'Sun Jun 03 11:26:10 JST 2012'
ISBN13 = 'isbn13'
Book's ID = '2'
First Name = 'Ichiro'
Last Name = 'Suzuki'
Author's ID = '2'

終わりに
unit テ ス ト や integration テ ス ト で 大 量 の デ ー タ が 必 要 に なる場合があると思いますが、特定の値である必要がなければ、Build Test Data プラグインを使用してみるのはいかがでしょうか。

▼ぐるーびーたん

第 4 話までのあらすじ

プログラマを目指して熊本から上京したぐるーびー

たん。今度は翻訳にチャレンジ !?

※この作品は、たいがいフィクションです。実在の人物、団体とは関係ありません。

ぐるーびーたん

第5話

25

G*Magazine vol.5

リリース情報 2012.06.03
GrailsGrails は、Groovy や Hibernate などをベースとしたフルスタックの Web アプリケーションフレームワークです。
URL: http://grails.org/
バージョン : 1.3.9, 2.0.4, 2.1.0.RC2■更新情報• 1.3.9 では、コマンドオブジェクトのバリデーションでインジェクトされた Bean が使えないバグに対応しました。
• 1.3.9 リリースノート : http://grails.org/1.3.9+Release+Notes• 山本さんのブログ :http://d.hatena.ne.jp/mottsnite/20120524/1337881977• 2.0.4 では、GrailsLog4jLoggerAdapter のパフォーマンス改善
や、コントローラを持たないビューやリソースのパフォーマ
ンス改善、いくつかのバグ対応が行われています。
• 2.0.4 リリースノート : http://grails.org/2.0.4+Release+Notes• 山本さんのブログ :http://d.hatena.ne.jp/mottsnite/20120523/1337787556• 2.1.0.RC2 では、コントローラを持たないビューやリソースのパフォーマンス改善や、いくつかのバグ対応が行われています。
• 2.1.0.RC2 リリースノート :http://grails.org/2.1.0.RC2+Release+Notes• 山本さんのブログ :http://d.hatena.ne.jp/mottsnite/20120523/1337776401

GroovyGroovy は、JavaVM 上で動作する動的言語です。
URL: http://groovy.codehaus.org/
バージョン : 1.7.10, 1.8.6, 2.0.0-rc-2■更新情報• 1.8.6 では、配列に contains メソッドが追加されたり、リス
トに collate メソッドが追加されたり、いくつかのバグ対応が行われています。
• 1.8.6 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=18245• 2.0.0-rc-2 では、rc1 から jar の依存関係などのバグ対応が行われています。
• 2.0.0-rc-2 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=18550

Griffon
Griffon は、デスクトップアプリケーションを開発するためのア
プリケーションフレームワークです。
URL: http://griffon.codehaus.org/
バージョン : 0.9.5■更新情報• 0.9.5 では、コンパイル前にプロジェクトをクリーンするオ
プションが追加されたり、いくつかのバグ対応が行われています。
• 0.9.5 リリースノート : http://docs.codehaus.org/display/
GRIFFON/Griffon+0.9.5#Griffon095-095

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

26 リリース情報

GradleGradle は、Groovy でビルドスクリプトを記述し実行するビルド管理ツールです。
URL: http://www.gradle.org/
バージョン : 1.0-rc-3■更新情報• 1.0-rc-3 では、Groovy ソースのコンパイル時に発生する例外に対応されています。
• 1.0-rc-3 リリースノート : http://wiki.gradle.org/display/
GRADLE/Gradle+1.0-rc-3+Release+Notes

GaelykGaelyk は、Groovy で記述する Google App Engine for Java 用のライトウェイトなフレームワークです。
URL: http://gaelyk.appspot.com/
バージョン : 1.2■更新情報• 1.2 では、Groovy 1.8.6、App Engine SDK 1.6.6 にアップグレー
ドし、Maven から利用可能となりました。
• 1.2 リリースノート : 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.6.6■更新情報• 1.6.6 では、管理コンソールの Quota Details に Search API の項目が追加されたり、Search API に関するクラスや属性が一部非推奨になったり、またいくつかのバグ対応が行われています。
• 1.6.6 リリースノート : http://code.google.com/p/
googleappengine/wiki/SdkForJavaReleaseNotes

GPars
GPars は、Groovy に直感的で安全な並行処理を提供するシステム
です。
URL: http://gpars.codehaus.org/
バージョン : 0.12GA

Groovy++Groovy++ は、Groovy 言語に対して静的な機能を拡張します。
URL: http://code.google.com/p/groovypptest/
バージョン : 0.9.0

Spock
Spock は、Java や Groovy 用のテストと仕様のためのフレームワー
クです。
URL: http://code.google.com/p/spock/バージョン : 0.6■更新情報• 0.6 では、Groovy 1.8, 2.0, Grails 2.0 のサポート、Mock や状況表示の改良、またいくつかのバグ対応が行われています。
• 0.6 リリースメール : https://groups.google.com/group/
spockframework/browse_thread/thread/c720a3871114666

GroovyServ
GroovyServ は、Groovy 処理系をサーバとして動作させることでgroovy コマンドの起動を見た目上高速化するものです。
URL: http://kobo.github.com/groovyserv/

G*Magazine vol.5
バージョン : 0.10
■更新情報

• 0.10 では、-v オプションで GroovyServ のバージョン表示や、–allow-from オプションでループバックアドレスを除いた‘localhost’ の解決ができるようになり、いくつかバグ対応が行われています。
• 0.10 リリースノート : http://kobo.github.com/groovyserv/
changelog.html#version-0-10-2012-03-30

Geb
Geb は、Groovy を使用した Web ブラウザを自動化する仕組みです。
URL: http://www.gebish.org/
バージョン : 0.7.0■更新情報• 0.7.0 では、フォームコントロールのショートカットがページやモジュールコンテンツでも動作するようになり、waitFor()
メソッド呼び出しでのタイムアウトメッセージをカスタマイ
ズできるようになったりと、いくつか新機能の追加や改良がされています。
• 0.7.0 リリースノート : http://www.gebish.org/manual/
current/project.html#070

Easyb
Easyb は、ビヘイビア駆動開発(Behavior Driven Development:BDD) 用のフレームワークです。
URL: http://www.easyb.org/
バージョン : 0.9.8

Gmock
Gmock は、Groovy 用のモック・フレームワークです。
URL: http://code.google.com/p/gmock/バージョン : 0.8.2■更新情報• 0.8.2 では、Groovy のバージョンが 1.8.4 になり、Grails 2.0 対
応といくつかのバグ対応がされています。
• 0.8.2 リリースブログ : http://grails.io/post/15568051467/
gmock-0-8-2-released-with-grails-2-0-support

HTTPBuilder
HTTPBuilder は、HTTP ベースのリソースに簡単にアクセスするための方法です。
URL: http://groovy.codehaus.org/modules/http-builder/バージョン : 0.5.2■更新情報• 0.5.2 では、エスケープされた URI クエリーパラメータの対応
や、AsyncHTTPBuilder のバグ対応、HttpClient 生成のカスタ
マイズ対応がされています。
• 0.5.2 チェンジログ : http://groovy.codehaus.org/modules/
http-builder/changes.html

CodeNarc
CodeNarc は、Groovy 向けの静的コード解析ツールです。
URL: http://codenarc.sourceforge.net/
バージョン : 0.17
■更新情報

• 0.17 では、新しいルールの追加や更新・拡張、Groovy 2.x 系のサポートや、いくつかバグ修正されています。
• 0.17 リリースノート : http://sourceforge.net/projects/
codenarc/files/codenarc/CodeNarc%20Version%200.17/

GMetrics
GMetrics は、Groovy ソースコードのサイズや複雑さを計算したり報告するためのツールです。
URL: http://gmetrics.sourceforge.net/
バージョン : 0.5■更新情報• 0.5 では、新しいメトリクスやメトリクスセット DSL のの追加、メソッドレベルのメトリクスの拡張などされています。
• 0.5 リリースノート : http://sourceforge.net/projects/
gmetrics/files/gmetrics-0.5/

GContracts
GContracts は、Groovy で契約プログラミングを行うためのフレームワークです。
URL: https://github.com/andresteingress/gcontracts
バージョン : 1.2.5■更新情報• 1.2.5 では、Groovy 1.8 対応や、Spock と一緒に使用した際のコンパイルエラー対応されています。
• 1.2.5 リリースノート : http://blog.andresteingress.
com/2012/01/16/gcontracts-1-2-5-released/

GroovyFX
GroovyFX は、JavaFX を Groovy で書きやすくするためのフレームワークです。
URL: http://groovyfx.org/
バージョン : 0.1■更新情報• 0.1 では、Grab 対応や、TableCell や ListCell がより簡単に作成できるようになり、またいくつかバグ修正されています。
• 0.1 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?version=18233&styleName=Text&project
Id=12531

GBenchGBench は、Groovy のためのベンチマーク・フレームワークです。
URL: http://code.google.com/p/gbench/
バージョン : 0.3■更新情報• 0.3 では、ベンチマークの自動化とマイクロベンチマークを計算する BenchmarkBuilder の追加や、@Benchmark のシス
テムプロパティの変更が行われています。
• 0.3 リリースノート :http://code.google.com/p/gbench/wiki/ReleaseNotes030

Betamax
Betamax は、HTTP 通信の内容を保存し再生するテストツールです。
URL: https://github.com/robfletcher/betamax
バージョン : 1.0

Caelyf
Caelyf は、Groovy で記述する Cloud Foundry 用のライトウェイト
なツールキットです。
URL: http://caelyf.cloudfoundry.com/
バージョン : 0.1

Vert.xVert.x は、非同期アプリケーション開発のためのフレームワークです。
URL: http://vertx.io/
バージョン : 1.0.1
リリース情報27

■企業スポンサー■個人サポーター
須江 信洋 様関谷 和愛 様
田中

明様

個人サポータ制度のお知らせ
JGGUG では , 昨年に引き続き 2012 年度も個人サポータを募集いたします。.
個人サポータとなっていただいた方には、一年間にわたって JGGUG が発行する G* Magazine（年数回刊。基本的に電子版として配布予定）に個人サポータとしてお名前を掲載します（掲載を希望しない旨お申し出いただけば掲載しません）。
個人サポータとなるには、まず supporters@jggug.org にメイルで• お名前• 予定金額G* Magazine へのご芳名掲載の可否をお知らせください。追って、運営委員より振込先の情報などを返信します。
皆様のサポートをお待ちしております。

日本 Grails/Groovy ユーザーグループ
代表

山田 正樹

G* Magazine vol.5 2012.06
http://www.jggug.org

発行人：日本 Grails/Groovy ユーザーグループ
編集長：川原正隆
編集：G* Magazine 編集委員（杉浦孝博、奥清隆）
デザイン：㈱ニューキャスト
表紙：川原正隆
編集協力：JGGUG 運営委員会
Mail：info@jggug.org© 2012 JGGUG 掲載記事の再利用についてはCreative Commons ライセンスによります。

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