Geb + Jenkins(Geb実行時のキャプチャをJenkinsのテストケースに紐付ける)

TwitterとかFacebookSNS疲れが著しいikikkoです。こんばんは。

最近久しぶりにGroovyを触ったので、生存確認の意味も込めてブログ書いておきます。


概要

Seleniumテストとかだと、実行時の画面のキャプチャを取っておきたいこともありますよね。で、せっかくキャプチャをとったはいいものの、そのキャプチャがどのテストに付随するものかがぱっと見分からないと、無駄な時間を過ごしてしまいます。

Jenkins上でテストを実行する前提として、Jenkinsのテストケースを表示する画面にそのテストケースで出力されたキャプチャが一緒に表示されると便利そうですよね。ということで、そんな設定をした画面を↓にお見せします。この画面を出すことが、今回のブログエントリの目標。

https://cacoo.com/diagrams/53iLDWTrizxRSpH2-54C59.png

Jenkinsでテストケースとファイルの紐付

Junit Attachements Pluginを使えば、テストケースに任意のファイルを紐付けることができます。

紐付方法は2通りあります。

  • テスト結果ファイル名に合わせてディレクトリを作成し、その中に紐付けるファイルを置く
    • テスト結果ファイル名:".../target/surefire-reports/TEST-foo.bar.MyTest.xml"
    • ファイルディレクトリ:".../target/surefire-reports/foo.bar.MyTest/"
  • 標準出力/エラー出力に、ファイルのパスを出力する
    • "[[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というのが気になったので、ちょっと試してみました。

ちなみに、クラウドと言ったらもちろんコレですよね。
http://pub.ne.jp/sakurabu/image/user/1208648202.jpg


概要

SauceLabsとは

Cross browser testing with Selenium - Sauce Labsは、クラウド上でSeleniumテストケースを実行することができるものです。自動でスクリーンショットやビデオを撮る機能があり、いわゆるSelenium 1はもちろんSelenium 2(WebDriver)も対応しています。200分/1ヶ月の無料枠やGithubアカウントでのログインもあり、チュートリアルも結構豊富なので、試すだけならすぐに試すことができます。

ちなみに、似たようなサービスとして"CloudTesting"というものもあります。残念ながらこちらはプログラマブルSelenium RCは対応してなく、Selenium IDEで出力されるHTML形式のテストケースしか実行できないようですが。

SauceLabsにはいくつかの機能が提供されています。

Sauce OnDemand
SauceLabs上のSelenium RC
Sauce Scout
手動でSauceLabs上のブラウザを操作できる機能
Sauce Builder
SauceLabsでの操作をサポートするFirefox plugin
Sauce Connect
イントラ内のWebサーバに対しても、SauceLabs上から参照できるようにする
Gebとは

通常のSelenium(WebDriver)を実行するだけではツマラナイので、今回はGebを使ってみます。Gebとは一言でいうと、Groovyを使ってJQuery風の要素指定ができるようにしたものです。"$('div')"といった形で、要素を指定できます。

Gebについての詳細は、JGGUGが発行しているG* Magagine Vol.1に導入編が載っているので、そちらも参照ください。

実践

今回作成したソースコードは、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を使えよハゲ」と怒られるのです。