Geb + Jenkins(Geb実行時のキャプチャをJenkinsのテストケースに紐付ける)
TwitterとかFacebookのSNS疲れが著しいikikkoです。こんばんは。
最近久しぶりにGroovyを触ったので、生存確認の意味も込めてブログ書いておきます。
概要
Seleniumテストとかだと、実行時の画面のキャプチャを取っておきたいこともありますよね。で、せっかくキャプチャをとったはいいものの、そのキャプチャがどのテストに付随するものかがぱっと見分からないと、無駄な時間を過ごしてしまいます。
Jenkins上でテストを実行する前提として、Jenkinsのテストケースを表示する画面にそのテストケースで出力されたキャプチャが一緒に表示されると便利そうですよね。ということで、そんな設定をした画面を↓にお見せします。この画面を出すことが、今回のブログエントリの目標。
Jenkinsでテストケースとファイルの紐付
Junit Attachements Pluginを使えば、テストケースに任意のファイルを紐付けることができます。
紐付方法は2通りあります。
- テスト結果ファイル名に合わせてディレクトリを作成し、その中に紐付けるファイルを置く
- 標準出力/エラー出力に、ファイルのパスを出力する
- "[[ATTACHMENT|/absolute/path/to/some/file]]"という形式で出力
まあどっちでもいいんですが、後者の方が若干楽なのかな。
Gebでキャプチャ出力
Selenium(WebDriver)のGroovyラッパーにGebというものがあります。で、GebのSeleniumGebReportingSpecを使えば、各テストが終了するときにキャプチャを自動で出力することができます。今回は、これを使ってみました。
GebやGebReportingSpecの詳細については、Slideshareの資料とか、適当にぐぐるとかしてみてください。
Geb + Jenkins
ということで、Gebテスト実行時にキャプチャファイルのパスを出力するようにします。
ScreenshotAndPageSourceReporterがキャプチャ出力用のクラスで、この中のgetFileメソッドで出力用のキャプチャファイルを用意しているので、このメソッドをフックしてファイルパスを出力するようにします。GebConfig.groovyらへんに仕込んでおけばいいでしょう。この設定を仕込んだGebテストをJenkins上で実行すれば、冒頭であげたスクリーンショットのようにテストケースとキャプチャを同じ画面に表示できます。
reporter = new ScreenshotAndPageSourceReporter() { @Override protected getFile(File dir, String name, String extension) { def file = super.getFile(dir, name, extension) println "[[ATTACHMENT|${file.absolutePath}]]" file } }
ちなみに、GebConfig.groovyとは↓のようなもの。
Geb の共通設定を書いておくファイルの位置づけでしょうか。デフォルトパッケージに配置するということなので、src/test/resources の直下に GebConfig.groovy を実装します。
http://hideoku.hatenablog.jp/entry/20121029/1357389342
以上、2013年最初のブログでした。それではみなさん良いお年を!
クラウド上でSeleniumスクリプトを走らせることができる、SourceLabsをGebで試してみたよ
確かJenkinsの生みの親が語る、継続的インテグレーションの未来 − @ITで出てきたSauceLabsというのが気になったので、ちょっと試してみました。
概要
SauceLabsとは
Cross browser testing with Selenium - Sauce Labsは、クラウド上でSeleniumテストケースを実行することができるものです。自動でスクリーンショットやビデオを撮る機能があり、いわゆるSelenium 1はもちろんSelenium 2(WebDriver)も対応しています。200分/1ヶ月の無料枠やGithubアカウントでのログインもあり、チュートリアルも結構豊富なので、試すだけならすぐに試すことができます。
ちなみに、似たようなサービスとして"CloudTesting"というものもあります。残念ながらこちらはプログラマブルなSelenium RCは対応してなく、Selenium IDEで出力されるHTML形式のテストケースしか実行できないようですが。
SauceLabsにはいくつかの機能が提供されています。
実践
今回作成したソースコードは、Github上に置いてます。
また、テスト結果はこちらのリンクに記録されています。スクリーンショットやビデオ、Seleniumの実行結果がこちらから参照できます。
前準備
ここでは、GebTestもしくはGetReportingTestを継承して、テストケースを作成する前提とします。
まず、SauceLabsのサーバを指定したDriverを作成します。createDriver()をオーバーライドして、username/accessKeyを指定したDriverを作ります。
final def USERNAME = 'XXXXXXXX' final def ACCESS_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' @Override WebDriver createDriver() { def dc = new DesiredCapabilities([ browserName: 'firefox', version: '3.6.', platform: Platform.WINDOWS, username: USERNAME, accessKey: ACCESS_KEY, name: "Hello, Sauce OnDemand with Geb!", ]) new RemoteWebDriver(new URL('http://ondemand.saucelabs.com:80/wd/hub'), dc) }
続いて、テストを実行した後に接続を切断するための処理を入れておきます。これをしておかないと(GebTestデフォルトのままだと)、SauceLabs側でテストが終了とみなされず、SauceLabsを利用出来る時間がどんどん消費されていくので、必ずやっておきましょう。
なお、@Afterアノテーションだとサブクラス側のメソッドが先に呼ばれてその後にスーパークラスの@afterメソッドが呼ばれるのですが、スーパークラス側ではすでに切断された状態で処理しようとするため、NullPointerExceptionが発生します。なので、ちょっとカッコ悪いですが、スーパークラスの@afterメソッドをオーバーライドして、先にスーパークラスの処理を行ってからdriver.quit()しています*1。
@Override void clearBrowserCookies() { super.clearBrowserCookies() browser.driver.quit() }
テストコード作成
ここでは、BacklogというBTSで「ログイン -> ダッシュボード -> プロジェクト」に遷移するだけの簡単なGebテストを実行してみます。
@Test void "ログインして1番目のプロジェクトの最新課題にコメントする"() { // ログインページ to LoginPage assert at(LoginPage) userId = 'demo' password = 'demo' submit.click() // ダッシュボードページ waitFor { at(DashboardPage) } firstProject.click() // プロジェクトページ waitFor { at(ProjectPage) } }
これで、SauceLabs側でGeb(Selenium)が走ります。上記のリンクで示したところから、スクリーンショットやビデオ、Seleniumの実行結果がを参照できます。一応、リンクをも一度ぺたり。
感想
スクリプトの作りが悪いのかもしれないけど、ちょっと いやかなり重かったです。ほんとは、「課題にコメントする」というのも実装しているのですが、SauceLabs上でテストしても遅くて高々画面4,5遷移しかしないのに多分5分以上レスポンスが全然返ってきませんでした。ローカルで走らせたときはまだそこまで時間がかからなかった30秒ぐらいで終わったんですけどねー。特にそういうドキュメントは見当たりませんでしたが、有料だとこの辺緩和されるのかな?とかも思ったり。
(自分にとっては)すぐさま実用的なものとはならないと思いますが、SeleniumやGebの復習ができたのでよしとします。
*1:Spock+Gebだとこの手法が使えなかったので断念しました。GebSpecの@afterをオーバーライドしようとすると、Spock側で「そんなことやっちゃだめよ、Specificationのfixtureを使えよハゲ」と怒られるのです。