G*Magazine Vol.1

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

はじめに

読者の皆さんは、普段Webアプリケーションでの機能テストはどのように行っていますか?今日では商用・OSSを問わず、様々なWebアプリケーション向けのテストツールが存在していますので、既にWeb機能テストを自動化している方も多いと思いますが、まだまだ手動で実施している方もいるのではないでしょうか。また、テストツールを導入したものの、プロジェクトの開発手法に合わなかったり、テストスクリプトを修正するコストが高く、保守されなくなってしまったケースもあるかもしれません。

本稿では、Groovyを用いたWebアプリケーション向けの機能テストライブラリであるGeb(「ジェブ」と発音します)を用いたWebテストの実施方法を紹介していきます。Gebはアジャイル開発と相性が良く、簡潔なDSLでテストスクリプトを記述することのできるテストライブラリですので、これからWebテストの自動化を検討している方や、現在利用しているテストツールに不満のある方にもお勧めのライブラリです。

初回は導入編として、Gebの概要とインストールから実行までを解説していきます。

Gebとは

Gebは、Luke Daley氏を中心に開発されているWebアプリケーション向けの機能テストを自動化するためのライブラリです。Internet Explorer, FireFox, Chrome などのブラウザを操作することが可能なSeleniumのWebDriverとJQueryライクな記述でコンテンツの操作や検査を可能にするAPIを組み合わせ、Groovyの豊かな表現力により簡潔なDSLでテストスクリプトを記述することができます。

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

Gebのコンセプト

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

jQueryライクなコンテンツ操作・検査API

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

// ページ上の全ての'div'要素を取得
$("div")
 
// ページ上の最初の'div'要素を取得
$("div", 0)
 
// ページ上のタイトル属性の値が'section'である全ての'div'要素を取得
$("div", title: "section")
 
// ページ上のclass属性が'main'である全ての'div'要素を取得
$("div.main")

Page Objectパターン

Page ObjectパターンではWebアプリケーションの画面を一連のオブジェクトとして表現し、テスト対象となる画面上のUIコンポーネントをモデル化します。これにより重複したコードを減らすことができますし、UIが変更された場合にもコードの修正が少なくなりますので、変更に強く再利用性の高い実装をすることができます。

Gebを使用するメリット

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

Seleniumとの比較

Seleniumはキャプチャ/プレイバックツールにカテゴリされるテストツール※です。Seleniumでは実際のブラウザ上でアプリケーションを操作し、その操作記録にassertなどの検証コマンドを追加してあとで再生してテストを行います。このキャプチャ/プレイバックのアプローチは、テストスクリプトが自動生成されるため一見便利なように思うかもしれませんが、問題点もあります。それは一度は手動でアプリケーションを操作しなければならないことです。つまり、事前にある程度正常に動作する状態になっていなければ、テストの実施どころか、テストのための記録も取ることができません。

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

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

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

Canoo WebTestとの比較

Canoo WebTest(以降、WebTest)はスイスのCanoo Engineering AG社により2002年から開発されているテストツールです。Geb同様スクリプトを記述してテストを行うアプローチを採用しており、通常はテストスクリプトはAntのビルドファイル形式で記述します。スクリプトの記述にはGroovyもサポートされているため、GroovyのAntBuilderを使用して記述することもできますが、簡潔な記述とまでは言い切れません。

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

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

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

Gebを使用したWebアプリケーションの機能テスト

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

対象のアプリケーションはいわゆるHello Worldです。テキストボックスにテキストを入力し【Greet】ボタンを押下すると、次画面に入力されたテキストを含めたメッセージが<h1>タグで表示される単純なものです。

 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 を選択します。

※日本語環境では「構成」です。

Gebの設定

Gebを使用するにはgeb-core.jarとWebDriverの実装が必要になります。通常はMavenまたはGradleなどのビルドツールまたは@Grab経由で取得します。Gebの現時点での最新バージョンは0.5.1です。ここではpom.xmlを使用して取得します。

xml
<dependency>
    <groupId>org.codehaus.geb</groupId>
    <artifactId>geb-core</artifactId>
    <version>RELEASE</version>
    <type>jar</type>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-firefox-driver</artifactId>
    <version>RELEASE</version>
    <type>jar</type>
    <scope>test</scope>
</dependency>

テストフレームワークの設定

GebのテストをEclipseから実行するために、ここではJUnitを使用します。

xml
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>RELEASE</version>
    <type>jar</type>
    <scope>test</scope>
</dependency>

テストケース

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

テスト条件入力値テスト手順期待する結果
Hello画面が表示されていることJGGUG1.テキストボックスに入力
2.Greetボタンを押下
Greeting画面に遷移すること
Hello, JGGUG! とメッセージが表示されること

テストスクリプトの実装

早速、前述のテストケースを実装してみます。ここではPage Objectパターンを適用する実装と適用しない実装の2例を紹介します。

Page Objectパターンを適用しない実装

WebTest.groovy
package hello;

import org.junit.Test
import geb.Browser

class WebTest {

    @Test
    void helloJGGUG() {
        Browser.drive('http://localhost:8080/Hello') {

            // Hello画面が表示されていること
            assert title == 'Hello'

            // テキストボックスに「JGGUG」と入力
            // Greetボタンを押下
            $('form').username = 'JGGUG'
            def greetButton = $('input', name:'greet')
            greetButton.click()

            // Greeting画面に遷移すること
            assert title == 'Greeting'

            // 「Hello, JGGUG!」とメッセージが表示されること
            assert $('h1').text() == 'Hello, JGGUG!'
        }
    }
}

Page Objectパターンを適用する実装

Page Objectパターンでは画面を1つのオブジェクトとして表現します。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')
        }
    }
}

Greet画面に対するPageクラスも同様です。

GreetingPage.groovy
package pages

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 {

    @Test
    void helloJGGUG() {
        Browser.drive(HelloPage) {

            // Hello画面が表示されていること
            assert at(HelloPage)

            // テキストボックスに「JGGUG」と入力
            // Greetボタンを押下
            username = 'JGGUG'
            greetButton.click()

            // Greeting画面に遷移すること
            assert at(GreetingPage)

            // 「Hello, JGGUG!」とメッセージが表示されること
            assert h1Text == 'Hello, JGGUG!'
        }
    }
}

Page Objectパターンを適用すると、画面内のUIコンポーネントに関するコードをPageクラス内に隠蔽することができるため、テストスクリプトが簡潔になり感覚的にもわかりやすくなります。

テストの実行

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

テストフレームワークとの統合

ここまでは、JUnitを使用してテストを実装してきましたが、Gebにはテストフレームワークと統合するためのjarが別途用意されていますので、こちらも試してみましょう。

pom.xmlに次の設定を追加してください。

xml
<dependency>
    <groupId>org.codehaus.geb</groupId>
    <artifactId>geb-junit4</artifactId>
    <version>RELEASE</version>
    <type>jar</type>
    <scope>test</scope>
</dependency>

このgeb-junit4.jarにはGroobyTestCaseクラスを継承したGebTestクラスと、GebTestクラスにレポート出力機能を追加したGebReportingTestクラスがあります。GebTestクラスを使用するとBrowserクラスが隠蔽されるため、よりシンプルな実装となります。

@RunWith(JUnit4)
class WebTestWithJUnitIntegration extends GebTest {

    @Test
    void helloJGGUG() {
        to HelloPage
        assert at(HelloPage)

        username = 'JGGUG'
        greetButton.click()
        assert at(GreetingPage)

        assert h1Text == 'Hello, JGGUG!'
    }
}

レポートの出力

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について紹介する予定です。ご期待ください。

著者紹介

  • 綿引 琢磨(わたびき たくま)
  • Groovy/Grails/Griffon/Java 界隈のやさぐれエンジニア。日本 Grails/Groovy ユーザーグループ運営委員。

G*Magazine Vol.1

Grailsをコントロールせよ! Part 1
Griffon 不定期便 〜第2回 バインディング編〜
CodeNarcを利用してGROOVYのコード品質を上げる ~第1回 CodeNarcとは~
GebではじめるWebテスト 〜第1回 導入編〜
Grails Plugin 探訪 第2回 ~Spock プラグイン~
リリース情報 2011.02.11
ぐるーびーたん 第1話