Upload
nobuhiro-sue
View
4.706
Download
0
Embed Size (px)
DESCRIPTION
Citation preview
入門Geb+Betamax
2011/11/22
JGGUGサポートスタッフ 須江 信洋
http://twitter.com/nobusue
http://d.hatena.ne.jp/nobusue
※資料の内容は個人としての意見・見解を述べたものであり、
所属する企業・組織が内容を保証するものではありません。
自己紹介
須江 信洋(すえ のぶひろ) Twitter: @nobusue
http://www.facebook.com/profile.php?id=732337788
かれこれ10年位、JavaEE関連の仕事をしてます
G*(Groovy関連技術)との関わり Groovyコミュニティ(JGGUG)サポートスタッフ
「プログラミングGROOVY」執筆チーム
「Groovy イン・アクション」翻訳チーム
Groovyで作ったBot飼ってます(@hatena_groovy)
2
本日のお題
テスト自動化について
Geb入門
Betamax入門
Geb+Spock+Betamaxでgrails test-app
3
テスト自動化、しましょうか?
Vモデル
4
http://ja.wikipedia.org/wiki/V%E3%83%A2%E3%83%87%E3%83%AB
ここはJUnitなどで
わりかし自動化
できている
ここは未だに
人海戦術が
主流
自動化できれば・・・
テスト実行に伴う人的コストが不要になる リファクタリングに取り組み易くなる
バグフィックスや機能修正によるリリース頻度を上げられる
ミドルウェアやOSのFix適用に躊躇しなくてよくなる
テストの品質を上げられる 手作業に完全ということはありえない
手作業は監査できない
5
とはいえ・・・
受け入れテスト(UAT)の完全自動化は大変 ならば、せめてスモークテストだけでも自動化を
人手によるテストやパフォーマンステストの前の関門として、CIのプロセスに組み込んでみては?
6
http://en.wikipedia.org/wiki/Smoke_testing
Gebる前に: Seleniumの系譜
7
Selenium1 (Selenium RC)
2004~
Selenium IDE
Selenium-Grid
WebDriver (Google)
2006~
Selenium2
Selenium2 +WebDriver
2009~
2011/07
Selenium2.0リリース
http://seleniumhq.org/docs/01_introducing_selenium.html#brief-history-of-the-selenium-project
Selenium1とWebDriver Selenium1の課題 テスト・ドライバーがブラウザ上で稼働するため、ブラウザのサンドボックスの制限を受ける
原理的に対応が難しい機能がある ファイルアップロードなど Ajax対応
WebDriver テスト・ドライバーがブラウザ外部で稼働するため上記の制限を受けない
Headless Driver(HtmlUnit)に対応 詳細な比較については以下http://www.asukaze.net/etc/webdriver/
8
WebDriver: Java APIサンプル
9
public class Selenium2Example { public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); driver.get("http://www.google.com"); WebElement element = driver.findElement(By.name("q")); element.sendKeys("Cheese!"); element.submit(); System.out.println("Page title is: " + driver.getTitle()); (new WebDriverWait(driver, 10)) .until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver d) { return d.getTitle().toLowerCase().startsWith("cheese!"); } }); System.out.println("Page title is: " + driver.getTitle()); driver.quit(); } }
10
ちょっとめんどい
そこでGeb(じぇぶ)ですよ
Groovyで構築されたWebDriverのラッパー jQueryライクなNavigator APIを提供 Page Objectパターンによる構造化
WebDriver単体でも使えるが、より使いやすく
2011/11/22時点での最新バージョンは0.6.1 GitHub上の最新は0.7.0-SNAPSHOT
多様なテストフレームワークと統合可能 Spock,EasyB JUnit3/4,TestNG Cucumber(Cuke4Duke)
11
http://www.gebish.org/
jQuery-like Navigator API
12
// CSS 3 selectors $("div.some-class p:first[title='something']") // Find via index and/or attribute matching $("h1", 2, class: "heading") $("p", name: "description") $("ul.things li", 2) // 'text' is special attribute for the element text content $("h1", text: "All about Geb") // Use builtin matchers and regular expressions $("p", text: contains("Geb")) $("input", value: ~/¥d{3,}-¥d{3,}-¥d{3,}/) // Chaining $("div").find(".b") $("div").filter(".c").parents() $("p.c").siblings()
Page Objectパターン
13
class LoginPage extends Page { static url = "http://myapp.com/login" static at = { heading.text() == "Please Login" } static content = { heading { $("h1") } loginForm { $("form.login") } loginButton(to: AdminPage) { loginForm.login() } } }
class AdminPage extends Page { static at = { heading.text() == "Admin Section" } static content = { heading { $("h1") } } }
Browser.drive { to LoginPage assert at(LoginPage) loginForm.with { username = "admin" password = "password" } loginButton.click() assert at(AdminPage) }
ログイン画面
管理画面
テスト
Gebの例: はてなキーワード検索
14
@Grapes([ @Grab("org.codehaus.geb:geb-core:0.6.1"), @Grab("org.seleniumhq.selenium:selenium-firefox-driver:2.12.0") ]) import geb.Browser Browser.drive { go "http://d.hatena.ne.jp/keyword/" assert title == "はてなキーワード - 話題の言葉がわかる、みんなで編集するキーワード" $("form.header-search").word = "Groovy" $("form.header-search").find("input", name:"submit").click() assert title == "はてな検索: Groovy" }
GebとSpockのインテグレーション
Gebと連携するSpockのテストケースとして以下が提供される geb.spock.GebSpec / GebReportingSpec
browserインスタンスの注入 WebDriverのBrowserクラスの初期化が不要
evidence取得の自動化 GebReportingSpecを利用すると、テストケースのメソッド終了時にスクリーンショット(PNG)が自動取得される
15
Geb ドキュメント&サンプル
The Book Of Geb http://www.gebish.org/manual/current/
かなり詳しいドキュメント
Gebソースコード https://github.com/geb/geb
Geb/Gradleサンプル https://github.com/geb/geb-example-gradle
16
ChromeDriver利用時の注意点
ChromeDriverを実行可能にしておくこと http://code.google.com/p/selenium/wiki/ChromeDriver
バイナリをダウンロード
http://code.google.com/p/chromium/downloads/list
パスに追加 or システムプロパティ webdriver.chrome.drive を設定
17
GebReportingSpecの例
18
class GoogleSpec extends GebReportingSpec { def "the first link should be wikipedia"() { when: to GoogleHomePage and: search.forTerm "wikipedia" then: at GoogleResultsPage and: firstResultLink.text() == "Wikipedia" when: firstResultLink.click() then: waitFor { at WikipediaPage } } }
GebSpec利用時の注意点
GebReportingSpecを利用する場合はレポート出力先のディレクトリを指定しておく必要がある 最も簡単なのはシステムプロパティを使うこと
groovy -Dgeb.build.reportsDir=/tempdir GebSpockReporting.groovy
19
Gebについて詳しくは・・・
G*Magazine http://grails.jp/g_mag_jp/
創刊号と第3号に、@bikisuke さんがGeb/Spockの技術情報を執筆
GitHub https://github.com/kimukou/gradlestudy/tree/master/geb-geb-example
@kimukou_26 さん作成サンプル
20
Betamax
WebサービスのRecord/Playback Proxy HTTPリクエスト/レスポンスをtapeに記録
tapeを利用してWebサービスをエミュレート
JUnit/Spockとのインテグレーション
vcr(Ruby)のクローン https://www.relishapp.com/myronmarston/vcr
vcrのcassetと互換性あり?(未確認)
21
http://robfletcher.github.com/betamax/
Hello, Betamax
22
<任意のディレクトリ>
│ build.gradle
└─src
└─test
└─groovy
MySpec.groovy
"gradle test"を実行すると、 src/test/resources/betamax/tapesにtapeが作成される
同じリクエストに対してはBetamaxがtapeを再生する デフォルトではURLとHTTPメソッドの対で同一性を判定
build.gradle
23
apply plugin: "groovy"
repositories {
mavenCentral()
}
dependencies {
groovy("org.codehaus.groovy:groovy-all:1.8.4")
testCompile("com.github.robfletcher:betamax:1.0")
testCompile(
"org.codehaus.groovy.modules.http-builder:http-builder:0.5.1") {
exclude module: "groovy"
exclude module: "httpclient"
}
testCompile("org.spockframework:spock-core:0.5-groovy-1.8") {
exclude module: "groovy-all"
}
}
MySpec.groovy
24
import betamax.*
import spock.lang.*
import org.junit.*
import groovyx.net.http.RESTClient
import org.apache.http.impl.conn.ProxySelectorRoutePlanner
class MySpec extends Specification {
@Rule Recorder recorder = new Recorder()
@Shared RESTClient http = new RESTClient()
def setupSpec() {
http.client.routePlanner = new ProxySelectorRoutePlanner(
http.client.connectionManager.schemeRegistry, ProxySelector.default)
}
@Betamax(tape="my tape")
def "various types of response data"() {
when:
def response = http.get(uri:"http://grails.org/")
then:
response.status == 200
}
}
その他のサンプル
今のところまとまったドキュメント等はないので、ソースコードからビルドして試すのがおすすめ https://github.com/robfletcher/betamax
そろそろGitには慣れておいた方がいい
ビルド時の注意点 SonaTypeのアカウント設定
テストが一部通らない・・・が無視してOK
25
SonaTypeのアカウント設定
素直にビルドすると以下のエラーが A problem occurred evaluating root project 'betamax'.
Cause: No such property: sonatypeUsername for class: org.gradle.api.internal.artifacts.publish.maven.deploy.groovy.DefaultGroovyMavenDeployer
SonaTypeのアカウントなんて持ってないよママン!
以下で対処してください gradle.propertiesを作成(値は空白で可) [gradle.properties] sonatypeUsername= sonatypePassword=
26
テストが一部通らない
時刻の扱いに問題あり(Timezoneを考慮していない)だが、テストケース側の問題なので無視してOK 一応pull requestしたけど放置されてます。。。
他にもいくつか問題あり。ぜひパッチを!
27
Grails + Geb + Betamax
ソースのexamples/grails-betamax以下
28
← ユニットテスト(Spock+Betamax)
← 機能テスト(Spock+Geb+Betamax)
← tape(Twitter API呼出し)
tape
YAMLでHTTPリクエスト/レスポンスを記録
29
!tape
name: twitter success
interactions:
- recorded: 2011-08-31T13:12:42.293Z
request:
method: GET
uri: http://search.twitter.com/search.json?q=betamax&rpp=10&page=1
headers:
Accept: application/json
Accept-Encoding: gzip,deflate
Host: search.twitter.com
Proxy-Connection: Keep-Alive
response:
status: 200
headers:
Age: '0'
Cache-Control: max-age=15, must-revalidate, max-age=300
Content-Encoding: gzip
Content-Type: application/json;charset=utf-8
Date: Wed, 31 Aug 2011 13:12:42 GMT
Expires: Wed, 31 Aug 2011 13:17:42 GMT
Server: hi
Vary: Accept-Encoding
Via: 1.1 varnish
X-Varnish: '2033991101'
body: |-
{
"completed_in": 0.072,
"max_id": 108888091493801987,
tapeの利用価値
Web APIにアクセスできない状況でもテストができる 新幹線で移動することが多い人向け
テストを高速化できる いちいちサーバーにアクセスしなくてすむ
テスト結果を安定化できる サーバー側の変化からテストを分離できる
レアケースに対するテストを容易にできる TwitterのAPI呼出し制限に引っ掛かった場合など
tapeを再利用(資産化)できる
30
Betamaxはまり道
基本的にはRecorderと@Betamaxだけで いけるはず! 組合せによっていろいろ起こります。。。。
とりあえずGroovy-1.8/HTTPBuilderの組合せがおすすめ
素のURLクラスを使うと、 java.io.IOException: Premature EOF ???
400 Bad Request ???
品質向上にご協力下さい
31
"Please raise issues on Betamax’s GitHub issue tracker. Forks and pull requests are more than welcome." by Rob Fletcher
32
ご静聴 ありがとう ございました