Geb で JavaScript のテストをしてみた #gadvent2012

 
こんにちは、@hideoku です。G* Advent Calendar 2012 の18日目を担当します。
よろしくお願いします。


きのう17日目は @nagai_masato さんの「Multiple Dispatch in Modern JVM Languages」でした。
あす19日目は @nightmare_tim さんです。お楽しみに。

前置き

Groovy を知ったのが、今年の5月でまだ半年くらいしか Groovy 歴がないヒヨッ子です。
Groovy → Spock → Gradle → Geb → Grails という感じで勉強しています。

「G* Advent Calendar 2012」の執筆者さん達は普段ブログなどを参考にさせてもらっている方々ばかりなので、若干ビビっていますがよろしくお願いします。

今回はブラウザテストのフレームワークである、Geb を取り上げたいと思います。

JavaScript にアクセスできる Geb

Geb では、JavaScript の変数にアクセスしたり、メソッドを実行することができます。
具体的には、"js" オブジェクトを使用します。「js.◯◯◯」という文法です。

http://www.gebish.org/manual/current/javascript.html#javascript_ajax_and_dynamic_pages

<html>
    <script type="text/javascript">
        var aVariable = 1;
        function addThem(a, b) {
            returna + b;
        }
    </script>
    <body>
    </body>
</html>

 

Browser.drive {
    assert js.aVariable == 1 
    assert js.addThem(1, 2) == 3
}

Geb を使ってはいましたが、JavaScript にアクセスするこの機能は使ったことがありませんでした。
Geb の JavaScript アクセスを検証したいと思います。

Geb で fizzbuzz のテストコードを書く

今回はこの機能を使って、JavaScript のテストコードを TDD で書いてみます。
お題は fizzbuzz です。

まず、Geb のテストコードです(SampleJsTest.groovy)。GebSpec を継承して、Spock で書きます。

package sample
import geb.spock.GebSpec

class SampleJsTest extends GebSpec {
    
    def setup() {
        go "file://localhost/workspace/JavaScriptTestByGeb/web-app/sample.html"
    }

    def "引数が 3 の倍数のとき 'fizz' を返す"() {
        expect:
        js.fizzbuzz(3) == 'fizz'
    }

    def "引数が 5 の倍数のとき 'buzz' を返す"() {
        expect:
        js.fizzbuzz(5) == 'buzz'
    }
    
    def "引数が 15 の倍数のとき 'fizzbuzz' を返す"() {
        expect:
        js.fizzbuzz(15) == 'fizzbuzz'
    }
    
    def "引数が 3 の倍数でもなく 5 の倍数でもないとき、引数の値をそのまま返す"() {
        expect:
        js.fizzbuzz(value) == value
        
        where:
        value << [1, 2]
    }
}

次にプロダクトコードにあたる、JavaScript ファイルです(sample.js)。

function fizzbuzz(value) {
    var result;

    if (value % 15 == 0) {
        result = 'fizzbuzz';
    } elseif (value % 3 == 0) {
        result = 'fizz';
    } elseif (value % 5 == 0) {
        result = 'buzz';
    } else {
        result = value;
    }
    return result;
}

最後に JavaScript が動く HTML ページです(sample.html)。JavaScript ファイルを指定しているだけです。

<html>
    <head>
        <script type="text/javascript"src="sample.js"></script>
    </head>
</html>

SampleJsTest.groovy を実行します。今回は Eclipse から JUnit テストとして実行しました。

Eclipse Geb テスト成功

なんの問題もなく、Geb で JavaScript にアクセスしてテストを実行することができました。
コードも余計なものがなくシンプルに書くことができています。

実行時間がネック

今回4ケースありましたが、テスト実行時間は合わせて3秒ちょっとでした。
そのうち約3秒間は1ケース目の実行前で Selenium WebDriver(今回は Chrome Driver を使用)の初期化に費やしてました。
ケース数が多くなればなるほど、最初の3秒間のオーバーヘッドは相対的に小さくなります。

他の JavaScript テストフレームワークを使ったことがないのでなんとも言えませんが、使えないことはないかなと思います。
ただし、TDD で Red/Green/Refactor のサイクルを細かく回転させていくとなると、3秒の初期化が毎度走るのはイライラするかもしれません。

JavaScript テストフレームワークとしての Geb

・"js" オブジェクトを使うことで、簡単に JavaScript 変数やメソッドにアクセスできます
・Geb を知っていればブラウザテストも JavaScript ユニットテストもできます
JUnit ベースなので、Jenkins などの CIサーバとの連動(レポート出力など)がラクです

もちろん JavaScript テストフレームワークとしてではなく、ブラウザテストのフレームワークとしても非常に使いやすいものとなっています。
ブラウザテストは大変そうと思っている人はぜひ Geb を触ってみてください。