地味だけどGebをgroovyにしている5Tips #SWTestAdvent


はじめに

このエントリーは ソフトウェアテストあどべんとかれんだー 2014 の9日目のエントリーです。
前日は@urasandesuさんの 『非公開メソッドの入れ替え - from "Prig: Open Source Alternative to Microsoft Fakes" Wiki -』でした。記事内の「迂廻路生成?と思われるかも」という言葉通り私も最初は?となりましたが、読み進めて行くとなるほど納得、以前レガシーコードと格闘していた私にはとても参考になるエントリーでした!

そして初めましての方は初めまして! @PoohSunnyと言います。TDD、スクラム、ソフトウェアテスト、G*、AngularJSあたりに興味があります。現在はカエルのマークの人事管理Saas作りに奮闘中です。
今日はGebというツールについて書きます。

前置き:Geb紹介

Gebとは

プログラミング言語Groovyを用いたWebアプリケーション向けの機能テストライブラリで、「じぇぶ」と読みます(「げぶ」ではない)。本家のページ(英語)には、「とてもgroovyなブラウザオートメーション」と書かれてします(groovyって単語には、「魅惑的な」とか「すばらしい」などの意味があります。以下本エントリー中のgroovyという単語は同じ意味で使っています)。さまざまな説明やサンプルコードも本家のページにあります。ライセンスはApache License, Version 2.0です。

日本語の紹介記事

日本語でも既に紹介エントリーやスライドが多数あります。ここではリンクの紹介だけしておきます。

今日のテーマ

Gebのホームページや上記エントリーを見ただけでも、「あ、Gebって良さそう!」って感じるかもしれませんが、実際使ってみると他にもいろいろとGebには地味な?便利機能があります。
今年一年、仕事でそこそこGebテストを書いてきた中で、いろんな「あーこれ地味だけどgroovyだわー」というのに出会ったので、それらを紹介します。
Gebを導入しようと思えたり、導入した際に使って見ようと思えたりしていただけるとハッピーです。

地味だけどGebをgroovyにしている5Tips

1.attribute取得時にマッチャーが使える

Gebの説明で真っ先に上がる良い点は、下記のようにJQueryライクな簡潔なAPIでwebのエレメントを取得できることです。

$("h1", text: "All about Geb")
$("div").find(".b")

で、このtext:XXXの部分には、ただテキストを入れるだけではなく、マッチャーを使うことができます(参考リンク)。
例えば、

$("p", text: contains("Geb"))

上記コードの場合は、テキストに「Geb」と入っているエレメントが全て取得されます。他にもcontainsとか、startWithがあり、時々お世話になります。ちなみに下記のように、

$("p", text: ~/p./).size() == 2

といったように正規表現も使うことができます。
とても便利ですが、反面意図しないエレメントを取得してしまう可能性があるので、その点ご注意ください。

Gebのドキュメントでは下記のような例を見つけました。

class GoogleResultsPage extends Page {
    static at = { waitFor { title.endsWith("Google Search") } }
...

2.waitの記述が楽

Gebでの基本的なwaitは

waitFor { 
    $("p.status").text() == "Asynchronous operation complete!"
}

というようにwaitFor{ 条件 }で記述できます。
私以前はJava - WebDriverで書いていたのですが、

wait.until(visibilityOfElementLocated(By.id("hoge"));

とか書いていた気がします。Gebだと同じことは

waitFor { $("div", id: "hoge").isDisplayed() } 

と書けます。見た目だいぶシンプルになったと思います。

もしページオブジェクトパターンで記述しているのであれば、下記のように書くこともできます。

class IndexPage extends Page {
  static at = {
    title == "Top Page"
  }
  static content = {
    saveButton(wait: true) { $("button", class: "btn") }
  }
}

saveButtonを利用する際、まだ表示されていなければ表示を待ってくれます。タイムアウトはGebConfigで設定したり、(wait: 30)のように引数で設定することもできます。

3.Cookieの自動クリア

Geb + Spockで使う時は、各メソッドの実行毎にCookieをクリアしてくれます(参考リンク)。変にキャッシュが残っていると、意図しない動作をすることがあるためです。
もちろん、自動でクリアをしてくれない方がいい場合もあって、その時はGebCongif.groovyにパラメーターを追加すればOKです。

GebConfig.groovy
autoClearCookies = false

さらに、Spockの@Stepwiseアノテーションをテストにつけると、Cookieはクリアされなくなります。@Stepwiseをつけるということは、各ステップ毎に連続してテストをしたいケースでしょうから、こういった細かい気遣いは嬉しいです。

4.シンタックスシュガー

続いて、本当に地味だったけど、使って嬉しかったシンタックスシュガー2選。

ボタンのdisableを取得

たとえば、ボタンのエレメントのdisableを取りたい!というときに、

deleteSelectedButton.@disabled == 'true'

上記コードでとれます(参考リンク)。

sendkey

WebDriverで書くと、

driver.FindElement(By.Id("firstname"));
textbox1.SendKeys("Hello World");

と書くSendKeyイベントは、Gebだと

$("input", id: "firstName").value("hoge")

と書けます。もっとサボるなら

$("input", name: "firstName") << "hoge"

Groovyのファイルへの書き込みとかと一緒です(参考リンク)。

5.Cloud Browser Testing対応

Gebは各種WebDriverに対応しており、マルチブラウザ対応しています。それだけでなく、リモートドライバー対応しているので、リモートマシンでテスト実行が可能です(参考リンク)。ここで面倒になるのが環境の構築やメンテです。その面倒を軽減するため、SauceLabsBrowserStackといった「remote web browsers as a service」があります。Gebはこれらのサービスを、GebConfig.groovyに追記して、Gradle pluginを入れることで比較的簡単に導入することができます(参考リンク)。

弊社の場合、もう少し手抜きをしていて、CloudBeesの[email protected]の、Sauce OnDemandというサービスを使っています。Build.gradleに数行追加するだけ([email protected]側で設定が必要)ですが、テストの画面キャプチャ取得や実行動画の録画!を自動でしてるのでとても便利です。

まとめに代えて

いかがでした?

以上、結構マニアックなものを含めましたが、紹介してみました。Gebは細かいところに粋な気遣いがあったりするので、まだ未体験の人は是非一度触ってみてください!

明日は!?

@shin_semiyaさんです。「テストの量と重点化の方針について」とのことでわくわくしています。よろしくお願いします。