yfj2’s Automatic Web Test Related Blog

yfj2のWEBテスト自動化に関わるブログ

GebとSpockでログをファイル出力したい

【Geb】【Tips】GebとSpockでログをファイル出力したい
著者:ふじさわゆうき

問題

  • GebとSpockでログをファイル出力したい
    • 例えば、テストのページ遷移を"title"をログ出力しておくことで、第三者に示す資料の材料となる

解決

  • Fileクラスを使って出力する
    • 以下、テストクラスごとのログ出力のプログラム例である
      • 「"target/" + LoggerTest.class.simpleName + ".log"」でクラス名によるログファイル出力をしている
      • "logger.delete()"でログファイルの初期化をしている
      • "logger.append"でログファイルに出力している
class LoggerTest extends GebSpec {

	@Shared File logger = new File("target/" + LoggerTest.class.simpleName + ".log")

	def "output log file"() {
		setup:
		logger.delete()

		when:
		go "http://www.yahoo.co.jp"

		then:
		waitFor{ title == "Yahoo! JAPAN"}
		logger.append("firstPage: " + title + "\n")

		when:
		$("form").p = "sample"
		$("input",value:"検索").click()
		logger.append("search: " + "sample" + "\n")

		then:
		waitFor{ title == "「sample」の検索結果 - Yahoo!検索"}
		logger.append("secondPage: " + title + "\n")
	}
}
  • 出力結果
    • target/LoggerTest.log
firstPage: Yahoo! JAPAN
search: sample
secondPage: 「sample」の検索結果 - Yahoo!検索

参考文献

GebとSpockでのスクリーンショットファイルの文字化けを正常にしたい

【Geb】【Tips】GebとSpockでのスクリーンショットファイルの文字化けを正常にしたい
著者:ふじさわゆうき

問題

  • GebとSpockでのスクリーンショットを出力した時に日本語で書かれていると文字化けしてしまう
  • 以下"正常系テスト"のスクリーンショットファイルが"___.png"のような日本語が化けたファイル名になってしまう
class HogeTest extends GebReportingSpec {
 def "正常系テスト "(){
 ・
 ・
 ・
 }
}

解決

  • GebConfig.groovyに以下追記する
import geb.report.ScreenshotReporter

reporter = new ScreenshotReporter() {
            @Override
            protected escapeFileName(String name) {
                name.replaceAll('[\\\\/:\\*?\\"<>\\|]', '_')
            }
        }

GebとSpockで同一テストケースで複数ブラウザ(クロスブラウザ)テストを実行したい

GebとSpockで同一テストケースで複数ブラウザ(クロスブラウザ)テストを実行したい
著者:ふじさわゆうき

問題

  • 同一のテストケースでクロスブラウザテストを実行したいが、"GebConfig.groovy"に設定があるため、ブラウザの切り替えが難しい

解決

実装

  1. whereで"driverName"を切り替える
  2. setupで"driverName"に応じたdriverをnewする
  3. cleanupでdriverを終了する
  4. "@Unroll"にアノテーションで、ブラウザごとのテスト結果にする
class GoogleWikipediaMainTest extends GebSpec {
	@Unroll
	def "first result for wikipedia search should be wikipedia"() {

		setup:
		switch(driverName){
			case "firefox" :
				driver = new FirefoxDriver()
				break
			case "chrome":
				driver = new ChromeDriver()
				break
			case "ie":
				driver = new InternetExplorerDriver()
				break
		}

		when:
		to GoogleHomePage

		then:
		at GoogleHomePage

		when:
		search("test")

		then:
		waitFor { at GoogleResultsPage }

		when:
		search("wikipedia")

		then:
		waitFor { at GoogleResultsPage }

		and:
		waitFor { firstResultLink.text() == "Wikipedia"}

		when:
		firstResultLinkClick()

		then:
		waitFor { at WikipediaPage }

		where:
		driverName << ["firefox", "chrome", "ie"]
	}

	def cleanup(){
		driver.quit()
	}
}

GebとSpockによるWebテストTips集

GebとSpockによるWebテストTips集
著者:ふじさわゆうき

  1. 問題: 自動テスト中に"org.openqa.selenium.WebDriverException: java.net.SocketException: Connection reset"が発生してテストが続行できない。途中でエラー終了してしまう。
  2. 問題: 同一のテストケースでクロスブラウザテストを実行したいが、"GebConfig.groovy"に設定があるためブラウザの切り替えが難しい
  3. 問題: GebとSpockでのスクリーンショットを出力した時に日本語で書かれていると文字化けしてしまう
  4. 問題: GebとSpockでログをファイル出力したい
  5. 問題: 取得したいタグが取得できていないが原因がわからずにトライアンドエラーになってしまい問題解決に時間がかかってしまう。
  6. 問題: クッキーに訪問履歴等を格納するWebサイトにおいて、それらの情報がクッキーに格納されているかテストしたいが、Webツールを使って手動で確認しなければならないので手間になっている
  7. 問題: Geb+Spockの正常系のテストにおいて、ユーザーID、パスワードを共通設定ファイルに定義しておくと全テストケースで共有できるので定義したい。しかし、Geb+Spockにおいてその方法がわからない
  8. 問題: Geb+SpockでJUnitのように複数テストクラスをグルーピング(TestSuite)して実行したいがわからない

【Geb】【Tips】WebDriverException SocketException Connection reset

【Geb】【Tips】WebDriverException SocketException Connection reset
著者:ふじさわゆうき

問題

  • 自動テスト中に"org.openqa.selenium.WebDriverException: java.net.SocketException: Connection reset"が発生してテストが続行できない。途中でエラー終了してしまう。
■エラーメッセージ
java.net.SocketException: Connection reset
Build info: version: '2.44.0', revision: '76d78cf323ce037c5f92db6c1bba601c2ac43ad8', time: '2014-10-23 13:11:40'
System info: host: '*****', ip: '*****', os.name: 'Windows Server 2008 R2', os.arch: 'amd64', os.version: '6.1', java.version: '1.7.0_25'
Driver info: driver.version: HtmlUnitDriver

■スタックトレース
org.openqa.selenium.WebDriverException: java.net.SocketException: Connection reset
Build info: version: '2.44.0', revision: '76d78cf323ce037c5f92db6c1bba601c2ac43ad8', time: '2014-10-23 13:11:40'
System info: host: '*****', ip: '*****', os.name: 'Windows Server 2008 R2', os.arch: 'amd64', os.version: '6.1', java.version: '1.7.0_25'
Driver info: driver.version: HtmlUnitDriver
	at java.net.SocketInputStream.read(SocketInputStream.java:189)
	at java.net.SocketInputStream.read(SocketInputStream.java:121)
	at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
	at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:78)
	at org.apache.commons.httpclient.HttpParser.readLine(HttpParser.java:106)
	at org.apache.commons.httpclient.HttpConnection.readLine(HttpConnection.java:1116)
	at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.readLine(MultiThreadedHttpConnectionManager.java:1413)
	at org.apache.commons.httpclient.HttpMethodBase.readStatusLine(HttpMethodBase.java:1973)
	at org.apache.commons.httpclient.HttpMethodBase.readResponse(HttpMethodBase.java:1735)
	at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1098)
	at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:398)
	at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:346)
	at com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:97)
	at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseFromWebConnection(WebClient.java:1439)
	at com.gargoylesoftware.htmlunit.WebClient.loadWebResponse(WebClient.java:1370)
	at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:326)
	at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:387)
	at org.openqa.selenium.htmlunit.HtmlUnitDriver.get(HtmlUnitDriver.java:220)
	at org.openqa.selenium.htmlunit.HtmlUnitDriver.get(HtmlUnitDriver.java:208)
	at geb.Browser.go(Browser.groovy:411)
	at geb.Browser.go(Browser.groovy:395)
	at geb.spock.GebSpec.methodMissing(GebSpec.groovy:54)

原因

  • 自動テスト対象のWEBサイトが攻撃とみなして接続を切断するため

解決

  • Gebのテスト実行を一定時間待ち状態にして1秒辺りのアクセス回数を制御する
    • Thread.sleep(<待ち時間(ms)>)
    • 以下例だと、1000ミリ秒(1秒)待ってから「go "http://example.com"」を実行する
    when:
        Thread.sleep(1000)
        go "http://example.com"

【入門】Geb+SpockではじめるWebテスト~リファクタリング編~

【入門】Geb+SpockではじめるWebテスト~リファクタリング編~
著者:ふじさわゆうき

この記事は、以下の記事の続きです。
初めて訪問した方は以下の記事を参照してください。

目次

  1. 今回の目的
  2. GoogleWikipediaTestの問題点
  3. 問題解決とリファクタリング(1)
  4. 問題解決とリファクタリング(2)
  5. 問題解決とリファクタリング(3)
  6. まとめ

1. 今回の目的

Geb本家で示されているテスト例のもとに作成した"GoogleWikipediaTest"の問題点を洗い出してリファクタリングすること
本家:http://www.gebish.org/manual/current/intro.html#testing

2. GoogleWikipediaTestの問題点

GoogleWikipediaTestの問題点を分析してみたところ、以下問題点があった。

  1. テストケース"GoogleWikipediaMainTest.groovy"がModuleなどの内部実装を意識しなければならない作りになっている
    • 「search.field.value("wikipedia")」は、「search("wikipedia")」にすれば内部実装を意識しなくてよくなる
    • 「firstResultLink.click()」は、「clickFirstResultLink」にすれば内部実装を意識しなくてよくなる
    • など
  2. GoogleSearchModuleのbuttonの指定が間違っている。サンプルでは実行していないのでエラーが発生していないだけ。

以下、現状のgoogle検索ボタンのHTML。inputタグは使用していない。

<button class="gbqfb" aria-label="Google Search" name="btnG" id="gbqfb">
	<span class="gbqfi gb_Sa"></span>
</button>

3. 部分一致のキーワード検索テストができない
以下のようなコードにするとエラーが発生する

class GoogleWikipediaMainTest extends GebSpec {

	def "first result for wikipedia search should be wikipedia"() {
		given:
		to GoogleHomePage

		expect:
		at GoogleHomePage

		when:
		search.field.value("test")

		then:
		waitFor { at GoogleResultsPage }

		when:
		search.field.value("wikipedia")
		
		then:
		waitFor { at GoogleResultsPage }

		and:
		firstResultLink.text() == "Wikipedia"

		when:
		firstResultLink.click()

		then:
		waitFor { at WikipediaPage }
	}
}

3. 問題解決とリファクタリング(1)

問題

  • テストケース"GoogleWikipediaMainTest.groovy"がModuleなどの内部実装を意識しなければならない作りになっている
    • 「search.field.value("wikipedia")」は、「search("wikipedia")」にすれば内部実装を意識しなくてよくなる
    • 「firstResultLink.click()」は、「clickFirstResultLink」にすれば内部実装を意識しなくてよくなる

リファクタ手順

  1. GoogleHomePageに"search"メソッドを追加する
  2. GoogleWikipediaMainTestの"search.field.value"を"search"に修正する
  3. GoogleWikipediaMainTestを実行して動作確認
  4. GoogleResultsPageに"clickFirstResultLink"メソッドを追加する
  5. GoogleWikipediaMainTestの"firstResultLink.click"を"firstResultLinkClick()"に修正する
  6. GoogleWikipediaMainTestを実行して動作確認

実装

  • "search"メソッドを追加する
class GoogleHomePage extends Page {

	// pages can define their location, either absolutely or relative to a base
	static url = "http://google.com/ncr"

	// “at checkers” allow verifying that the browser is at the expected page
	static at = { title == "Google" }

	static content = {
		// include the previously defined module
		search { module GoogleSearchModule, buttonValue: "Google Search" }
	}
        
        //"search"メソッドを追加
	public void search(String keyword){
		search.field.value(keyword)
	}
}
  • "search.field.value"を"search"に修正
class GoogleWikipediaMainTest extends GebSpec {

	def "first result for wikipedia search should be wikipedia"() {
		given:
		to GoogleHomePage

		expect:
		at GoogleHomePage

		when:
                //"search.field.value"を"search"に修正
		search("wikipedia")

		then:
		waitFor { at GoogleResultsPage }

		and:
		firstResultLink.text() == "Wikipedia"

		when:
		firstResultLink.click()

		then:
		waitFor { at WikipediaPage }
	}
}
  • "clickFirstResultLink"メソッドを追加する
class GoogleResultsPage extends Page {
	static at = { title.endsWith "Google Search" }
	static content = {
		// reuse our previously defined module
		search { module GoogleSearchModule, buttonValue: "Search" }

		// content definitions can compose and build from other definitions
		results { $("div.g") }
		result { i -> results[i] }
		resultLink { i -> result(i).find("a") }
		firstResultLink { resultLink(0) }
	}
	//firstResultLinkClickを追加
	public void firstResultLinkClick(){
		firstResultLink.click()
	}
}
  • "firstResultLink.click()"を"firstResultLinkClick()"に修正する
class GoogleWikipediaMainTest extends GebSpec {

	def "first result for wikipedia search should be wikipedia"() {
		given:
		to GoogleHomePage

		expect:
		at GoogleHomePage

		when:
                //"search.field.value"を"search"に修正
		search("wikipedia")

		then:
		waitFor { at GoogleResultsPage }

		and:
		firstResultLink.text() == "Wikipedia"

		when:
                //"firstResultLink.click()"を"firstResultLinkClick()"に修正
		firstResultLinkClick()

		then:
		waitFor { at WikipediaPage }
	}
}

4. 問題解決とリファクタリング(2)

問題

  • GoogleSearchModuleのbuttonの指定が間違っている。サンプルでは実行していないのでエラーが発生していないだけ。以下、現状のgoogle検索ボタンのHTML。inputタグは使用していない。
<button class="gbqfb" aria-label="Google Search" name="btnG" id="gbqfb">
	<span class="gbqfi gb_Sa"></span>
</button>

リファクタ手順

  1. GoogleSearchModuleの"buttonValue"を"buttonName"に変更する
  2. GoogleSearchModuleの"$("input", value: buttonValue)"を$("button", name: buttonName)"に変更する
    • inputタグがbuttonタグに変更になっていたので修正する
    • また、valueだとデザインの変更を受けやすいので、nameに変更する。nameの場合は、httpリクエストに利用されるため、変更の可能される可能性が低い
  3. GoogleSearchModuleの変更に対して、GoogleResultsPageとGoogleHomePageを修正する
  4. GoogleWikipediaMainTestを実行して動作確認

実装

  • "$("input", value: buttonValue)"を$("button", name: buttonName)"に変更する
class GoogleSearchModule extends Module {

	// a parameterised value set when the module is included
	def buttonName

	// the content DSL
	static content = {

		// name the search input control “field”, defining it with the jQuery like navigator
		field { $("input", name: "q") }

		// the search button declares that it takes us to the results page, and uses the
		// parameterised buttonName to define itself
		button(to: GoogleResultsPage) {
			$("button", name: buttonName)
		}
	}
}
  • GoogleSearchModuleの変更に対して、GoogleResultsPageとGoogleHomePageを修正する
    • search{ module GoogleSearchModule, buttonName: "btnG" }
class GoogleHomePage extends Page {

	// pages can define their location, either absolutely or relative to a base
	static url = "http://google.com/ncr"

	// “at checkers” allow verifying that the browser is at the expected page
	static at = { title == "Google" }

	static content = {
		// include the previously defined module
		search{ module GoogleSearchModule, buttonName: "btnG" }
	}

	public void search(String keyword){
		search.field.value(keyword)
	}
}


class GoogleResultsPage extends Page {
	static at = { title.endsWith "Google Search" }
	static content = {
		// reuse our previously defined module
		search{ module GoogleSearchModule, buttonName: "btnG" }

		// content definitions can compose and build from other definitions
		results { $("div.g") }
		result { i -> results[i] }
		resultLink { i -> result(i).find("a") }
		firstResultLink { resultLink(0) }
	}
	//firstResultLinkClickを追加
	public void firstResultLinkClick(){
		firstResultLink.click()
	}
}

5. 問題解決とリファクタリング(3)

問題

  • 部分一致のキーワード検索テストができない
    • 以下のようなコードにするとエラーが発生する
    • 現状のコードだと、完全一致のajax動作を前提としていることが原因
    • ここで先ほどのGoogleSearchModuleのbuttonの指定リファクタリングが生きてくる
    • 要は、検索と同時に検索ボタンをクリックしてやればよい
class GoogleWikipediaMainTest extends GebSpec {
	def "first result for wikipedia search should be wikipedia"() {
		given:
		to GoogleHomePage

		expect:
		at GoogleHomePage

		when:
		search("test")

		then:
		waitFor { at GoogleResultsPage }

		when:
		search("wikipedia")

		then:
		waitFor { at GoogleResultsPage }

		and:
		firstResultLink.text() == "Wikipedia"

		when:
		firstResultLinkClick()

		then:
		waitFor { at WikipediaPage }
	}
}

リファクタ手順

  1. GoogleResultsPageに"public void search(String keyword)"を追加する
  2. GoogleHomePage,GoogleResultsPageの"public void search(String keyword)"に"search.button.click()"を追加する
    • "wikipedia"で検索した場合は、検索結果に合致したページがあったためにajaxにより検索結果が表示された。しかし、"test"の場合は、合致したページがajaxによる検索結果が表示されないために検索ボタンを明示的に押してやる必要がある。("test"でajax結果が出た場合は、ブラウザキャッシュが残っているはずなのでクリアしてから再度、試してみてください)
  3. "waitFor { firstResultLink.text() == "Wikipedia"}"と"waitFor"を追記する
    • waitForがないと、firstResultLinkが表示される前に判定してしまい、エラーになってしまうのでそれを防ぐ
  • GoogleResultsPageに"public void search(String keyword)"を追加する
  • GoogleResultsPageの"public void search(String keyword)"に"search.button.click()"を追加する
class GoogleResultsPage extends Page {
	static at = { title.endsWith "Google Search" }
	static content = {
		// reuse our previously defined module
		search{ module GoogleSearchModule, buttonName: "btnG" }

		// content definitions can compose and build from other definitions
		results { $("div.g") }
		result { i -> results[i] }
		resultLink { i -> result(i).find("a") }
		firstResultLink { resultLink(0) }
	}
	//firstResultLinkClickを追加
	public void firstResultLinkClick(){
		firstResultLink.click()
	}
        public void search(String keyword){
		try {
			search.field.value(keyword)
			search.button.click()
		} catch (Exception e) {
		}
	}
}


  • GoogleHomePageの"public void search(String keyword)"に"search.button.click()"を追加する
class GoogleHomePage extends Page {

	// pages can define their location, either absolutely or relative to a base
	static url = "http://google.com/ncr"

	// “at checkers” allow verifying that the browser is at the expected page
	static at = { title == "Google" }

	static content = {
		// include the previously defined module
		search{ module GoogleSearchModule, buttonName: "btnG" }
	}

	public void search(String keyword){
		try {
			search.field.value(keyword)
			search.button.click()
		} catch (Exception e) {
		}
	}
}
  • "waitFor { firstResultLink.text() == "Wikipedia"}"と"waitFor"を追記する
class GoogleWikipediaMainTest extends GebSpec {
	def "first result for wikipedia search should be wikipedia"() {
		given:
		to GoogleHomePage

		expect:
		at GoogleHomePage

		when:
		search("test")

		then:
		waitFor { at GoogleResultsPage }

		when:
		search("wikipedia")

		then:
		waitFor { at GoogleResultsPage }

		and:
		waitFor { firstResultLink.text() == "Wikipedia"}

		when:
		firstResultLinkClick()

		then:
		waitFor { at WikipediaPage }
	}
}

6. まとめ

  1. Spockに記述するテスト部分には実装(Module)を表に出さないようにする。pageオブジェクトのメソッドとして定義することでそれを実現する
    • 例:searchとしては、こうすることで変更に強い実装となる
      • "問題解決とリファクタリング(3)"のような"search.button.click()"は、pageオブジェクトのメソッドにしておいたことで、テストコードを汚すことなくリファクタすることができた
  2. 処理が早くてassertでエラーが発生する場合は、waitForを追加すること
    • 例: firstResultLink.text() == "Wikipedia" → waitFor { firstResultLink.text() == "Wikipedia"}

変更点まとめ(diff)

diff --git a/src/main/groovy/module/GoogleSearchModule.groovy b/src/main/groovy/module/GoogleSearchModule.groovy
index 7ed091e..96d33b1 100644
--- a/src/main/groovy/module/GoogleSearchModule.groovy
+++ b/src/main/groovy/module/GoogleSearchModule.groovy
@@ -6,7 +6,7 @@
 class GoogleSearchModule extends Module {
 
 	// a parameterised value set when the module is included
-	def buttonValue
+	def buttonName
 
 	// the content DSL
 	static content = {
@@ -15,9 +15,9 @@
 		field { $("input", name: "q") }
 
 		// the search button declares that it takes us to the results page, and uses the
-		// parameterised buttonValue to define itself
+		// parameterised buttonName to define itself
 		button(to: GoogleResultsPage) {
-			$("input", value: buttonValue)
+			$("button", name: buttonName)
 		}
 	}
 }
\ No newline at end of file
diff --git a/src/main/groovy/page/GoogleHomePage.groovy b/src/main/groovy/page/GoogleHomePage.groovy
index 5e5fdbf..0cb547b 100644
--- a/src/main/groovy/page/GoogleHomePage.groovy
+++ b/src/main/groovy/page/GoogleHomePage.groovy
@@ -13,6 +13,14 @@
 
 	static content = {
 		// include the previously defined module
-		search { module GoogleSearchModule, buttonValue: "Google Search" }
+		search{ module GoogleSearchModule, buttonName: "btnG" }
+	}
+
+	public void search(String keyword){
+		try {
+			search.field.value(keyword)
+			search.button.click()
+		} catch (Exception e) {
+		}
 	}
 }
\ No newline at end of file
diff --git a/src/main/groovy/page/GoogleResultsPage.groovy b/src/main/groovy/page/GoogleResultsPage.groovy
index aa50b09..bd25c5d 100644
--- a/src/main/groovy/page/GoogleResultsPage.groovy
+++ b/src/main/groovy/page/GoogleResultsPage.groovy
@@ -4,15 +4,24 @@
 import module.GoogleSearchModule
 
 class GoogleResultsPage extends Page {
+	static url = "https://www.google.com/?gws_rd=ssl"
 	static at = { title.endsWith "Google Search" }
 	static content = {
 		// reuse our previously defined module
-		search { module GoogleSearchModule, buttonValue: "Search" }
+		search{ module GoogleSearchModule, buttonName: "btnG" }
+		resultLinks(wait:true){ $("li" , class:"g")}
+		firstResultLink(wait:true){ $("li" , class:"g" , 0).$("a")}
+	}
+	//firstResultLinkClickを追加
+	public void firstResultLinkClick(){
+		firstResultLink.click()
+	}
 
-		// content definitions can compose and build from other definitions
-		results { $("div.g") }
-		result { i -> results[i] }
-		resultLink { i -> result(i).find("a") }
-		firstResultLink { resultLink(0) }
+	public void search(String keyword){
+		try {
+			search.field.value(keyword)
+			search.button.click()
+		} catch (Exception e) {
+		}
 	}
 }
diff --git a/src/test/groovy/main/GoogleWikipediaMainTest.groovy b/src/test/groovy/main/GoogleWikipediaMainTest.groovy
index 1590200..12559ea 100644
--- a/src/test/groovy/main/GoogleWikipediaMainTest.groovy
+++ b/src/test/groovy/main/GoogleWikipediaMainTest.groovy
@@ -6,7 +6,6 @@
 import page.WikipediaPage
 
 class GoogleWikipediaMainTest extends GebSpec {
-
 	def "first result for wikipedia search should be wikipedia"() {
 		given:
 		to GoogleHomePage
@@ -15,16 +14,22 @@
 		at GoogleHomePage
 
 		when:
-		search.field.value("wikipedia")
+		search("test")
+
+		then:
+		waitFor { at GoogleResultsPage }
+
+		when:
+		search("wikipedia")
 
 		then:
 		waitFor { at GoogleResultsPage }
 
 		and:
-		firstResultLink.text() == "Wikipedia"
+		waitFor { firstResultLink.text() == "Wikipedia"}
 
 		when:
-		firstResultLink.click()
+		firstResultLinkClick()
 
 		then:
 		waitFor { at WikipediaPage }

【入門】Geb+SpockではじめるWebテスト~GitHub + JenkinsによるWEBテスト自動化編~

【入門】Geb+SpockではじめるWebテスト~GitHub + JenkinsによるWEBテスト自動化編~
著者:ふじさわゆうき

この記事は、以下の記事の続きです。
初めて訪問した方は以下の記事を参照してください。

目次

  1. 前回までのあらすじ
  2. 今回の目的
  3. GitHubとは
  4. Jenkinsとは
  5. GitとSourceTreeインストール
  6. GitHubへソースをアップする
  7. JenkinsインストールとGitプラグインのインストール
  8. Jenkins+GitHubでテストを自動実行する
  9. Webテストを継続的かつ自動的に実行するフロー

1. 前回までのあらすじ

  1. Gebとは何かの説明
  2. Gebのメリット説明
  3. 「Eclipse + maven + Geb + Spock」での環境構築説明
  4. サンプルプログラム実装
    1. google検索⇒検索結果⇒WIKIという流れのWebテスト実施
    2. 「Geb + Spock」による上記Webテストの実施
  5. クロスブラウザの説明
  6. スクリーンショット出力方法の説明
  7. Mavenコマンドによるテスト自動実行方法の説明

2. 今回の目的

  • "GitHub"と"Jenkins"を使ってWebテストを継続的、かつ自動的に実行する環境を構築すること
  • 全体のフローは以下の通り
  • f:id:yfj2:20141130171051p:plain

3. GitHubとは

以下、GitHub - Wikipediaより引用

  • GitHub(ギットハブ)はソフトウェア開発プロジェクトのための共有ウェブサービスである
  • Gitバージョン管理システムを使用する
  • Ruby on RailsおよびErlangで記述されており、GitHub社によって保守されている
  • 主な開発者はChris Wanstrath、PJ Hyett、Tom Preston-Wernerである
  • GitHub商用プランおよびオープンソースプロジェクト向けの無料アカウントを提供している。
  • 2009年のユーザー調査によると、GitHubは最もポピュラーなGitホスティングサイトとなった

4. Jenkinsとは

以下、Jenkins - Wikipediaより引用

  • JenkinsとはJavaで書かれたオープンソース継続的インテグレーションツールである
  • このプロジェクトはHudsonからフォークされた。オラクルが2010年12月にHudsonの商標を登録したことによるものである
  • ビルドはバージョン管理システムにおけるコミットでのトリガ、cronライクのメカニズムを通したスケジューリング、他のビルドが完了した時の構築、特定のビルドURLによるリクエストといった様々な方法で起動することができる

5. GitとSourceTreeインストール

  1. 以下のサイトからWindows用のGitをダウンロードしてインストール画面を起動する
    • 2015/05/26時点だと"Ver1.9.5"がダウンロード可能
    • Git
  2. インストール設定
    • インストール先: "C:\Program Files\Git"
    • f:id:yfj2:20141130173129p:plain
    • Adjusting your PATH environment: "Run Git from the Windows Command Prompt"
      • デフォルトはUse Git Bash onlyだが、これは使いにくいのでダメ。"Use Git from the Windows Command Prompt"を選択すること。cmd.exe、PowerShell.exe、MinGW/MSYSのbash.exeなど、他のコマンドラインシェルからもGitコマンドを使えるようになる
      • f:id:yfj2:20141130172755p:plain
  3. SourceTree for Windowsのインストール

6. GitHubへソースをアップする

  1. GitHubにユーザー登録する
    • username , email , passwordの3つを入力して"Sing Up for GitHub"をクリック。確認メールが送られてくるので認証すれば完了と簡単!
    • f:id:yfj2:20141130174730p:plain
  2. リポジトリ"GoogleWikipediaTest"を作成する。
    • f:id:yfj2:20141130175149p:plain
    • f:id:yfj2:20141130175926p:plain
  3. SourceTreeを使って"GoogleWikipediaTest"をクローンします
  4. Gitクローンしたフォルダ"C:\gitrepository\GoogleWikipediaTest"にEclipseワークスペースにある以下フォルダをコピーする
    • GoogleWikipediaTest\driver
    • GoogleWikipediaTest\src
    • GoogleWikipediaTest\pom.xml
  5. Windowsのコマンドプロンプトを立ち上げて、以下、コマンドを実行する
    • git config --global user.email "hoge@gmail.com"←GitHubに登録したメールアドレス
    • git config --global user.name "YukiFujisawa"←GitHubに登録したユーザー名
    • git add -f IEDriverServer.exe
    • git add -f choromedriver.exe
  6. SourceTreeを使ってGitHubにソースをアップ(push)する
    1. 全てのソースをステージングエリアに登録する
    2. コミットする
    3. pushする
    • f:id:yfj2:20141130182856p:plain
    • f:id:yfj2:20141130184226p:plain
  7. GitHubにアップされたことを確認する

f:id:yfj2:20141130191604p:plain

7. JenkinsインストールとGitプラグインのインストール

  1. Jenkins下記サイトからダウンロードしてインストールする
  2. Git pluginのインストール
    1. Jenkinsの管理 > プラグインの管理 > 利用可能
      • Git Client Plugin
      • Git Server Plugin
      • GitHub API Plugin
      • GitHub Plugin
    2. "ダウンロードして再起動後にインストール"をクリックする
  3. Java, Mavenの設定
    1. Jenkinsの管理 > システムの設定
      • JDK > JDK追加 > "自動インストール"のチェックを外す
        • 名前: jdk1.7.0_79
        • JAVA_HOME: C:\Program Files\Java\jdk1.7.0_79
      • Maven > Maven追加 > "自動インストール"のチェックを外す
        • 名前: maven-3.2.5
        • MAVEN_HOME: C:\apache-maven-3.2.5
    2. "保存"をクリックする
  4. Jenkinsを再起動する
    • f:id:yfj2:20141130194200p:plain

8. Jenkins+GitHubでテストを自動実行する

  1. "GoogleWikipediaTest"実行用のジョブを作成する
    1. "新規ジョブ作成"をクリック
      • ジョブ名: GoogleWikipediaTest
      • 選択: フリースタイル・プロジェクトのビルド
      • f:id:yfj2:20141130194758p:plain
    2. ジョブの設定
      • ソースコード管理 > Git
      • Repository URL: GitHubのRepositoryを指定する
      • Credentials: GitHubのユーザー名、パスワードを設定する
      • ビルド > ビルド手順の追加 > Mavenの呼び出し
        • 使用するMaven: maven-3.2.5
        • ゴール: test
  2. ジョブの実行
    • Jenkins > GoogleWikipediaTest > ビルド実行
    • f:id:yfj2:20141130202214p:plain
  3. テスト結果を確認する
    1. Jenkins > GoogleWikipediaTest > ビルド履歴 > "実行日付"をクリック
    2. "Console Output"をクリック
    3. ログの一番下にテスト結果が表示される
    • f:id:yfj2:20141130202545p:plain

9. Webテストを継続的かつ自動的に実行するフロー

Webテストを継続的かつ自動的に実行するフローは以下の通りとなる

  1. Eclipseにて「Geb + Spock」でWEBテスト作成
  2. 完成したWEBテストを"C:\gitrepository\GoogleWikipediaTest"にコピーする
  3. SourceTreeを使ってGitHubにソースをアップ(push)する
  4. Jenkins(http://localhost:8080/)にアクセスしてビルド実行
    • テストスケジュールが設定できるので、設定すれば定期実行も可能
  5. テスト結果を確認する