yfj2’s Automatic Web Test Related Blog

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

GebとSpockでテストケースの中でクッキー(cookie)の値をテストしたい

【Geb】【Tips】GebとSpockでテストケースの中でクッキー(cookie)の値をテストしたい
著者:ふじさわゆうき

問題

  • クッキーに訪問履歴等を格納するWebサイトにおいて、それらの情報がクッキーに格納されているかテストしたいが、Webツールを使って手動で確認しなければならないので手間になっている

解決

  • クッキーの情報をGebとspockで取得できるようにして自動テストすれば解決する

実装

  • seleniumのライブラリを使って、クッキーを管理するクラス(GebCookieUtilクラス)を作成する
    • "driver.manage()"でOptionsを取得する
    • "options.getCookies()"でクッキーのリストを取得する
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriver.Options;

public class GebCookieUtil {

	private Options options = null;

	public GebCookieUtil(WebDriver driver) {
		this.options = driver.manage();
	}

	/**
	 * Cookiesコンソールに出力します
	 */
	public void printCookies() {
		System.out.println("--start getCookies-----");
		for (Cookie cookie : options.getCookies()) {
			System.out.println(String.format("key: %s, value: %s",
					cookie.getName(), cookie.getValue()));
		}
		System.out.println("--end getCookies-----");
	}

	/**
	 * クッキーから値を取得します
	 * 
	 * @param key
	 * @return
	 */
	public String getCookieVal(String key) {
		String result = null;
		for (Cookie cookie : options.getCookies()) {
			if (cookie.getName().equals(key)) {
				result = cookie.getValue();
				break;
			}
		}
		return result;
	}

        /**
	 * クッキーに値をセットします
	 * 
	 * @param key
	 * @param val
	 */
	public void setCookieVal(String key, String val) {
		options.addCookie(new Cookie(key, val));
	}
}
  • "new GebCookieUtil(driver)"で、GebCookieUtilをdriverで初期化している
  • "@Shared"でテストケース共通でクッキーを取り出せるようにしている
  • "cookieUtil.getCookieVal("JV")"で、"JV"に合致するクッキーの値を取得する
  • 以下、例だと、Yahooは、検索後に"JV"というキーでクッキーに値を記録していることがテストできる
import geb.spock.GebSpec
import spock.lang.Shared
import util.GebCookieUtil

class CookieUtilTest extends GebSpec {

	@Shared GebCookieUtil cookieUtil = new GebCookieUtil(driver)

	def "output cookie"() {
		when:
		go "http://www.yahoo.co.jp"

		then:
		waitFor{ title == "Yahoo! JAPAN"}
		cookieUtil.printCookies()
		assert cookieUtil.getCookieVal("JV") == null

		when:
		$("form").p = "sample"
		$("input",value:"検索").click()

		then:
		waitFor{ title == "「sample」の検索結果 - Yahoo!検索"}
		cookieUtil.printCookies()
		assert cookieUtil.getCookieVal("JV") != null
	}
}
  • 出力結果
--start getCookies-----
key: btpdb.2wzBV9u.dGZjLjE0NDcxNDU, value: UkVRVUVTVFMuMA
key: btpdb.2wzBV9u.dGZjLjE0MzQzNDg, value: VVNFUg
key: B, value: 0v43bbpaao770&b=3&s=vt
--end getCookies-----
--start getCookies-----
key: B, value: 0v43bbpaao770&b=3&s=vt
key: SGL, value: oIPUi_mbLv0rvzxfn3RiwyOcEu5XVFDvMP8hqs.NSjxcmNUHFKrcW2A1Hiv94CcPm92FKmgCZbzT7Cz1R54EKfflu_T1YVBuFhc72Hhjbp73_s8HCGWZufrYt5VkJTR5934wHIBE6Nih03mi1sdhnmYpanyFuOiW2kz.P3gAD.zufV4baMXr8ZSS0rPEXdqJTc7mDFm9rtg-
key: JV, value: LgRZRkUq.R_PaPKPFI8dHc1pZfoYZlCYP_19xcf1_hKIvK5dcw5rFM0DkDNIl7XLrOnhfO5Xa6uUGFy6rAT2I2GOnSJn8owoDEvJjy5_AgGH.prYycoGGkHFoYKvFgQpAb9xnfOoQgenrwkcMLox.hA1649ZFGS7lqIlzJXCkA_7qYSkEeRBLy5bM9LTt8i_c9oK3Dz5gj4b.si6igf4y8tTJkd51J.JpYUjP_aGXWrPd4ac_ioh0NavQs2hfcCAQ1enfs8pNJ4ThWIuipotIhi.O2r_aflzQZtrEh7BBnNXE4U_18BS7fMKm2FvHt100pxWUEghsrE.E8etAoOlJeJ1i_boBrC_pb9qIP2Qf8NyeXesnaghII6yw5lu.ReMntJBiyzqev9k9jkyd99aDovHAXMf6vlAGOr2QqIW64R11rb2fJgQ6OeHD14v9fwk.tmvKlxA12CTpHTNkUe91xtvVpWDfiBytYbiacM-
--end getCookies-----

GebとSpockで取得したタグを確認したい

【Geb】【Tips】GebとSpockで取得したタグを確認したい
著者:ふじさわゆうき

問題

  • 取得したいタグが取得できていないが原因がわからずにトライアンドエラーになってしまい問題解決に時間がかかってしまう。

原因

  • タグ検索結果をログ出力しないために手さぐりの解決になってしまっていること

解決

  • タグの検索結果をコンソールログに出力することで、どのようなミスをしているのか確認できるようにする。そうすることで、問題の切り分けが可能になる
  • 以下、ヤフートップページにある"inputタグ"全部をコンソールログに出力するプログラムのサンプル
  • コンソールログに出力することで、"inputタグ"から絞り込むためのヒントとなる
    • 「$("input").each」はgroovyの命令で、"inputタグ"の配列をloopする命令
    • "it"は、"input"タグのこと
      • 詳しくは、「groovy クロージャ it」でgoogle検索してみること
    • "it.getAttribute("name")"は、"input"タグのname属性を取得するメソッド
class DebugTest extends GebSpec {

	def "output debug log"() {
		when:
		go "http://www.yahoo.co.jp"

		then:
		waitFor{ title == "Yahoo! JAPAN"}
		$("input").each{
			println "name: " + it.getAttribute("name") +
					", type: " + it.getAttribute("type") +
					", value: " + it.getAttribute("value")
		}
	}
}
  • 実行結果
name: p, type: text, value: 
name: , type: submit, value: 検索
name: search.x, type: hidden, value: 1
name: fr, type: hidden, value: top_ga1_sa
name: tid, type: hidden, value: top_ga1_sa
name: ei, type: hidden, value: UTF-8
name: aq, type: hidden, value: 
name: oq, type: hidden, value: 
name: afs, type: hidden, value: 
name: p, type: text, value: 
name: , type: submit, value: 検索
name: search.x, type: hidden, value: 1
name: fr, type: hidden, value: top_ft
name: tid, type: hidden, value: top_ft
name: ei, type: hidden, value: UTF-8

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"