GebとSpockでWebテストを自動化せよ<br />2011/10/17  @JJUG CCC 2011 Fall<br /> JJUG幹事/ JGGUGサポートスタッフ 須江 信洋<br />http://twitter.com/nobu...
自己紹介<br />須江 信洋(すえ のぶひろ)<br />Twitter: @nobusue<br />http://www.facebook.com/profile.php?id=732337788<br />かれこれ10年位、JavaEE...
本日のお題<br />なぜテスト自動化が大切なのか<br />Webテスト自動化ツール Seleniumの系譜<br />Gebとは<br />Spockとは<br />GebとSpockのインテグレーション<br />3<br />
テスト自動化できてますか?<br />Vモデル<br />4<br />ここは未だに<br />人海戦術が<br />主流<br />ここはJUnitなどで<br />わりかし自動化<br />できている<br />http://ja.wiki...
自動化できれば・・・<br />テスト実行に伴う人的コストが不要になる<br />リファクタリングに取り組み易くなる<br />バグフィックスや機能修正によるリリース頻度を上げられる<br />ミドルウェアやOSのFix適用に躊躇しなくてよくな...
Continuous Delivery<br />UATまで自動化することで道が拓ける<br />6<br />http://www.amazon.co.jp/dp/0321601912<br />
なぜ自動化が進まないのか?<br />テスト自動化にコストがかかりすぎる<br />アプリ側の問題: テスト自動化を想定していない<br />ツールの問題<br />アプリの変更に追随するのが大変<br />そもそも自動化できない場合がある<b...
Seleniumの系譜<br />8<br />2004~<br />Selenium1(Selenium RC)<br />Selenium2<br />Selenium IDE<br />2009~<br />Selenium2<br />...
Selenium1とWebDriver<br />Selenium1の課題<br />テスト・ドライバーがブラウザ上で稼働するため、ブラウザのサンドボックスの制限を受ける<br />原理的に対応が難しい機能がある<br />ファイルアップロード...
WebDriver: Java APIサンプル<br />10<br />public class Selenium2Example  {<br />  public static void main(String[] args) {<br /...
Geb(じぇぶ)とは<br />http://www.gebish.org/<br />Groovyで構築されたWebDriverのラッパー<br />jQueryライクなNavigator APIを提供<br />Page Objectパター...
jQuery-like Navigator API<br />12<br />// CSS 3 selectors<br />$("div.some-class p:first[title='something']")<br />// Find...
Page Objectパターン<br />13<br />class LoginPage extends Page {<br />    static url = "http://myapp.com/login"<br />    static...
Gebの例: はてなキーワード検索<br />14<br />@Grapes([<br />    @Grab("org.codehaus.geb:geb-core:latest.release"),<br />    @Grab("org.s...
Spock(すぽっく)とは<br />http://code.google.com/p/spock/<br />Groovyで構築されたBDDフレームワーク<br />Groovyの動的型を活用したDSLを提供<br />Power Asser...
Power Assert<br />def a = 1<br />def b = 2<br />def c = 3<br />assert (a+b)*c == 5<br />途中結果や、どこでfailしたかまで教えてくれる。assertEqu...
可読性の高いテストケース<br />17<br />def "subscribers receive published events at least once"() {<br />   when: publisher.send(event)...
GebとSpockのインテグレーション<br />Gebと連携するSpockのテストケースとして以下が提供される<br />geb.spock.GebSpec / GebReportingSpec<br />browserインスタンスの注入<b...
GebReportingSpecの例<br />19<br />@Grab("org.codehaus.geb:geb-spock:0.6.0")<br />@Grab("org.spockframework:spock-core:0.5-gr...
GebSpec利用時の注意点<br />Spock-0.5(2011/10時点)ではGroovyの@Grabを利用する場合は、依存関係の兼ね合いで以下が必要<br />@GrabExclude("org.codehaus.groovy:groo...
JGGUGからのお知らせ<br />G*ワークショップ<br />だいたい月1回のペースでG*関連の勉強会を実施しています<br />次回は11/22予定、Gebの詳しい話を予定<br />詳細は http://www.jggug.org/ で...
ご静聴ありがとうございました<br />22<br />
Upcoming SlideShare
Loading in …5
×

JJUG CCC 2011 Fall / Web test automation with Geb and Spock

4,386 views

Published on

Published in: Technology

JJUG CCC 2011 Fall / Web test automation with Geb and Spock

  1. 1. GebとSpockでWebテストを自動化せよ<br />2011/10/17 @JJUG CCC 2011 Fall<br /> JJUG幹事/ JGGUGサポートスタッフ 須江 信洋<br />http://twitter.com/nobusuehttp://d.hatena.ne.jp/nobusue<br />※資料の内容は個人としての意見・見解を述べたものであり、<br />所属する企業・組織が内容を保証するものではありません。<br />
  2. 2. 自己紹介<br />須江 信洋(すえ のぶひろ)<br />Twitter: @nobusue<br />http://www.facebook.com/profile.php?id=732337788<br />かれこれ10年位、JavaEE関連の仕事をしてます<br />G*(Groovy関連技術)との関わり<br />Groovyコミュニティ(JGGUG)サポートスタッフ<br />「プログラミングGROOVY」執筆チーム<br />「Groovy イン・アクション」翻訳チーム<br />Groovyで作ったBot飼ってます(@hatena_groovy)<br />2<br />
  3. 3. 本日のお題<br />なぜテスト自動化が大切なのか<br />Webテスト自動化ツール Seleniumの系譜<br />Gebとは<br />Spockとは<br />GebとSpockのインテグレーション<br />3<br />
  4. 4. テスト自動化できてますか?<br />Vモデル<br />4<br />ここは未だに<br />人海戦術が<br />主流<br />ここはJUnitなどで<br />わりかし自動化<br />できている<br />http://ja.wikipedia.org/wiki/V%E3%83%A2%E3%83%87%E3%83%AB<br />
  5. 5. 自動化できれば・・・<br />テスト実行に伴う人的コストが不要になる<br />リファクタリングに取り組み易くなる<br />バグフィックスや機能修正によるリリース頻度を上げられる<br />ミドルウェアやOSのFix適用に躊躇しなくてよくなる<br />テストの品質を上げられる<br />手作業に完全ということはありえない<br />手作業は監査できない<br />5<br />
  6. 6. Continuous Delivery<br />UATまで自動化することで道が拓ける<br />6<br />http://www.amazon.co.jp/dp/0321601912<br />
  7. 7. なぜ自動化が進まないのか?<br />テスト自動化にコストがかかりすぎる<br />アプリ側の問題: テスト自動化を想定していない<br />ツールの問題<br />アプリの変更に追随するのが大変<br />そもそも自動化できない場合がある<br />ツールの制限など<br />7<br />
  8. 8. Seleniumの系譜<br />8<br />2004~<br />Selenium1(Selenium RC)<br />Selenium2<br />Selenium IDE<br />2009~<br />Selenium2<br />+WebDriver<br />Selenium-Grid<br />2006~<br />2011/07<br />Selenium2.0リリース<br />WebDriver<br />(Google)<br />http://seleniumhq.org/docs/01_introducing_selenium.html#brief-history-of-the-selenium-project<br />
  9. 9. Selenium1とWebDriver<br />Selenium1の課題<br />テスト・ドライバーがブラウザ上で稼働するため、ブラウザのサンドボックスの制限を受ける<br />原理的に対応が難しい機能がある<br />ファイルアップロードなど<br />Ajax対応<br />WebDriver<br />テスト・ドライバーがブラウザ外部で稼働するため上記の制限を受けない<br />Headless Driver(HtmlUnit)に対応<br />詳細な比較については以下http://www.asukaze.net/etc/webdriver/<br />9<br />
  10. 10. WebDriver: Java APIサンプル<br />10<br />public class Selenium2Example {<br /> public static void main(String[] args) {<br />WebDriver driver = new FirefoxDriver();<br />driver.get("http://www.google.com");<br />WebElement element = driver.findElement(By.name("q"));<br />element.sendKeys("Cheese!");<br />element.submit();<br />System.out.println("Page title is: " + driver.getTitle());<br /> (new WebDriverWait(driver, 10))<br /> .until(new ExpectedCondition<Boolean>() {<br /> public Boolean apply(WebDriver d) {<br /> return d.getTitle().toLowerCase().startsWith("cheese!");<br /> }<br /> });<br />System.out.println("Page title is: " + driver.getTitle());<br />driver.quit();<br /> }<br />}<br />
  11. 11. Geb(じぇぶ)とは<br />http://www.gebish.org/<br />Groovyで構築されたWebDriverのラッパー<br />jQueryライクなNavigator APIを提供<br />Page Objectパターンによる構造化<br />2011/10時点での最新バージョンは0.6<br />多様なテストフレームワークと統合可能<br />Spock,EasyB<br />JUnit3/4,TestNG<br />Cucumber(Cuke4Duke)<br />11<br />
  12. 12. jQuery-like Navigator API<br />12<br />// CSS 3 selectors<br />$("div.some-class p:first[title='something']")<br />// Find via index and/or attribute matching<br />$("h1", 2, class: "heading")<br />$("p", name: "description")<br />$("ul.thingsli", 2)<br />// 'text' is special attribute for the element text content<br />$("h1", text: "All about Geb")<br />// Use builtin matchers and regular expressions<br />$("p", text: contains("Geb"))<br />$("input", value: ~/d{3,}-d{3,}-d{3,}/)<br />// Chaining<br />$("div").find(".b")<br />$("div").filter(".c").parents()<br />$("p.c").siblings()<br />
  13. 13. Page Objectパターン<br />13<br />class LoginPage extends Page {<br /> static url = "http://myapp.com/login"<br /> static at = { heading.text() == "Please Login" }<br /> static content = {<br /> heading { $("h1") }<br />loginForm { $("form.login") }<br />loginButton(to: AdminPage) { loginForm.login() }<br /> }<br />}<br />ログイン画面<br />Browser.drive {<br /> to LoginPage<br /> assert at(LoginPage)<br />loginForm.with {<br /> username = "admin"<br /> password = "password"<br /> }<br />loginButton.click()<br /> assert at(AdminPage)<br />}<br />テスト<br />class AdminPage extends Page {<br /> static at = { heading.text() == "Admin Section" }<br /> static content = {<br /> heading { $("h1") }<br /> }<br />}<br />管理画面<br />
  14. 14. Gebの例: はてなキーワード検索<br />14<br />@Grapes([<br /> @Grab("org.codehaus.geb:geb-core:latest.release"),<br /> @Grab("org.seleniumhq.selenium:selenium-firefox-driver:latest.release")<br />])<br />import geb.Browser<br />Browser.drive {<br /> go "http://d.hatena.ne.jp/keyword/"<br /> assert title == "はてなキーワード - 話題の言葉がわかる、みんなで編集するキーワード"<br /> $("form.header-search").word = "Groovy"<br /> $("form.header-search").find("input", name:"submit").click()<br /> assert title == "はてな検索: Groovy"<br />}<br />
  15. 15. Spock(すぽっく)とは<br />http://code.google.com/p/spock/<br />Groovyで構築されたBDDフレームワーク<br />Groovyの動的型を活用したDSLを提供<br />Power Assertで問題箇所を容易に特定可能<br />可読性の高いテストケース<br />データ・ドリブン・テストにより多数のテストパターンをコンパクトに記述可能<br />テストケースはJUnitから実行可能<br />15<br />
  16. 16. Power Assert<br />def a = 1<br />def b = 2<br />def c = 3<br />assert (a+b)*c == 5<br />途中結果や、どこでfailしたかまで教えてくれる。assertEquals()とかを組み合わせる必要ナシ。<br />16<br />
  17. 17. 可読性の高いテストケース<br />17<br />def "subscribers receive published events at least once"() {<br /> when: publisher.send(event)<br /> then: (1.._) * subscriber.receive(event)<br /> where: event << ["started", "paused", "stopped"]<br />}<br />def "length of Spock's and his friends' names"() {<br /> expect:<br />name.size() == length<br /> where:<br /> name | length<br /> "Spock" | 5<br /> "Kirk" | 4<br /> "Scotty" | 6<br />}<br />
  18. 18. GebとSpockのインテグレーション<br />Gebと連携するSpockのテストケースとして以下が提供される<br />geb.spock.GebSpec / GebReportingSpec<br />browserインスタンスの注入<br />WebDriverのBrowserクラスの初期化が不要<br />エビデンス取得の自動化<br />GebReportingSpecを利用すると、テストケースのメソッド終了時にスクリーンショット(PNG)が自動取得される<br />18<br />
  19. 19. GebReportingSpecの例<br />19<br />@Grab("org.codehaus.geb:geb-spock:0.6.0")<br />@Grab("org.spockframework:spock-core:0.5-groovy-1.8")<br />@GrabExclude("org.codehaus.groovy:groovy-all")<br />@Grab("org.seleniumhq.selenium:selenium-firefox-driver:latest.release")<br />import geb.spock.GebReportingSpec<br />class FunctionalReportingSpec extends GebReportingSpec {<br /> def "Hatena Keyword Search Top"() {<br /> when:<br /> go "http://d.hatena.ne.jp/keyword/" <br /> then:<br /> title == "はてなキーワード - 話題の言葉がわかる、みんなで編集するキーワード"<br /> }<br /> def "Hatena Keyword Search Result"() {<br /> when:<br /> $("form.header-search").word = "Groovy"<br /> $("form.header-search").find("input", name:"submit").click()<br /> then:<br /> assert title == "はてな検索: Groovy"<br /> }<br />}<br />
  20. 20. GebSpec利用時の注意点<br />Spock-0.5(2011/10時点)ではGroovyの@Grabを利用する場合は、依存関係の兼ね合いで以下が必要<br />@GrabExclude("org.codehaus.groovy:groovy-all")<br />GebReportingSpecを利用する場合はレポート出力先のディレクトリを指定しておく必要がある<br />最も簡単なのはシステムプロパティを使うこと<br />groovy -Dgeb.build.reportsDir=/tempdirGebSpockReporting.groovy<br />20<br />
  21. 21. JGGUGからのお知らせ<br />G*ワークショップ<br />だいたい月1回のペースでG*関連の勉強会を実施しています<br />次回は11/22予定、Gebの詳しい話を予定<br />詳細は http://www.jggug.org/ で<br />G*Magazine<br />http://grails.jp/g_mag_jp/<br />JGGUGが発行している電子雑誌です。<br />創刊号と第3号に、@bikisukeさんがGeb/Spockの技術情報を執筆されています。<br />21<br />
  22. 22. ご静聴ありがとうございました<br />22<br />

×