Contenu connexe
Similaire à 脱・独自改造! GebでWebDriverをもっとシンプルに (20)
脱・独自改造! GebでWebDriverをもっとシンプルに
- 3. 3
自己紹介
名前:玉川 紘子(たまがわ ひろこ)
所属:株式会社SHIFT ソフトウェアテスト事業本部
技術開発部
コミュニティ:STAR(テスト自動化研究会)
日本Jenkinsユーザ会
- 5. 5
「実践 SSeelleenniiuumm WWeebbDDrriivveerr」を
少しだけお手伝いしました
n 翻訳+付録Bは玉川竜司さん
n 私は付録Aとして、Seleniumと
Jenkinsの連携について寄稿させて頂
きました
※竜司さんとは親戚ではありません
今回は書籍の発売記念を兼ねてということで、
竜司さんのおまけで声をかけていただきました。
- 8. 8
Gebのお話に行く前に
WWeebbDDrriivveerr、そのままでは微妙ですよね
n ちょっとしたことを書くにも、長い。。。
// テキスト入力
WebElement element = driver.findElement(By.name(“hoge”));
element.clear();
element.sendKeys();
// プルダウンの選択
Select select = new
Select(driver.findElement(By.name(“fuga”)));
select.selectByValue(“00”);
n 大体みんな同じようなラッパーを作っている
n と、前回の勉強会に出て思いました。
- 9. 9
Gebのお話に行く前に
「あるある」で共感している場合なのか
n みんなで同じものを作るのは勿体ない
n OSSで提供されているライブラリも色々
n FluentLenium(Java)
n Geb(Groovy)
n テスト対象製品に依存しないような改良は、独自に行うの
ではなく既存ライブラリに頼ってしまおう
- 10. 10
GGeebbとは
Gebで便利になること
n 読み方は「じぇぶ」
n http://www.gebish.org/
n Groovyで動くWebDriverのラッパー
n jQueryライクでわかりやすいLocator
n コード量が少なく、すっきり書ける
n テスト自動化研究会で@kyon_mmさんから教えてもらいま
した
- 12. 12
サンプルコード
Gebで便利になること
import geb.Browser
Browser.drive {
go http://myapp.com/login
assert $(h1).text() == Please Login
$(“p”, text:”hoge”)
$(form.login).with {
username = admin
password = password
login().click()
}
assert $(h1).text() == Admin Section
}
特定のURLを開いて
見出しを確認
フォームに入力してログイン
見出しを確認
- 13. 13
Gebで便利になること
サンプルコードをJJaavvaaWWeebbDDrriivveerrで書くと
// importは省略
WebDriver driver = new FirefoxDriver();
driver.get(“http://myapp.com/login”);
assertThat(driver.findElement(By.tag(“h1”)).getText(), is(“Please Login”));
WebElement form = driver.findElement(By.cssSelector(“form.login”));
WebElement userName = form.findElement(By.name(“username”));
userName.clear();
userName.sendKeys(“admin”);
WebElement password = form.findElement(By.name(“password”));
password.clear();
password.sendKeys(“password”);
form.findElement(By.name(“login”)).click();
assertThat(driver.findElement(By.tag(“h1”)).getText(), is(“Admin Section”));
- 14. 14
Gebで便利になること
メリット① 記述量の少なさ
n コードが短くなるポイントがいくつもある
import geb.Browser
Browser.drive {
go http://myapp.com/login
assert $(h1).text() == Please Login
$(form.login).with {
username = admin
password = password
login().click()
}
assert $(h1).text() == Admin Section
}
いちいちdriver.**と
書かなくてもOK
jQueryライクな
セレクタ
form内の要素は
さらに簡単に記述
(name属性を使う)
- 16. 16
Gebで便利になること
メリット② 「あるある」が解決済み
n テキスト入力のシンプル化
// Javaの場合、テキスト入力が長くなって面倒なので
WebElement element = driver.findElement(By.id(“hoge”));
element.clear();
element.sendKeys(“fuga”);
// 1行で出来るようにする
MyDriver.setText(By.id(“hoge”), “fuga”);
// Gebの場合、そもそも1行で書ける
$(“#hoge”).value(“fuga”)
n 割愛しますがプルダウンなども同様
- 17. 17
Gebで便利になること
メリット② 「あるある」が解決済み
n 設定系はGebConfig.groovyに集約
n クラスパス直下にこのファイル名で配置すると自動的に読み込まれる
// WebDriverインスタンスの生成
driver = { new FirefoxDriver() }
// 要素を見つけるときの待ち時間
waiting {
timeout = 10
retryInterval = 0.5
}
// テスト環境のURL
baseUrl = ‘http://localhost:8000/example/’
- 18. 18
Gebで便利になること
メリット③ もちろんPPaaggeeOObbjjeeccttもサポート
class ExamplePage extends Page {
// browser.toに対応
static url = “http://www.example.com/”
// browser.atに対応
static at = { title = “Example Page” }
// 操作したい各要素のlocatorを定義
static content = {
textUserName { $(“input[name=user_name]”) }
textMailAddress { $(“input[name=mail_address]”) }
}
}
Browser.drive {
to ExamplePage // ←urlで指定したURLへ遷移
/** 略 */
at ExamplePage // ←atの条件でassert
}
- 20. Gebで便利になること
メリット④ GGrroooovvyy//SSppoocckkの嬉しい機能が使える
20
n ブロックを使ってテストのフェーズを表現できる
// テストの準備と後片付けの部分を明示
class LoginSpec extends GebSpec {
def “IDとPWの組み合わせが正しい場合にログインできる” {
setup:
to “http://www.example.com/login/”
when:
$(“#loginId”).value(“user01”)
$(“#password”).value(“pass01”)
$(“#login”).click()
then:
at http://www.example.com/home/
cleanup:
//
}
}
- 21. Gebで便利になること
メリット④ GGrroooovvyy//SSppoocckkの嬉しい機能が使える
21
n データ駆動テストがシンプルに書ける
// 異なるID/PWでログイン結果を検証
class LoginSpec extends GebSpec {
def “IDとPWの組み合わせが正しくない場合ログインに失敗する” {
when:
$(“#loginId”).value(loginId)
$(“#password”).value(password)
$(“#login”).click()
then:
$(“#error”).text() == errorMessage
where:
loginId | password || errorMessage
“” | “pass01” || “ログインIDを入力してください”
“user01” | “” || “パスワードを入力してください”
“hoge” | “fuga” || “IDとパスワードの組み合わせが正しくありません”
}
}
↑入力と期待値の間は「||」で分ける
- 22. Gebで便利になること
メリット④ GGrroooovvyy//SSppoocckkの嬉しい機能が使える
22
n モジュールが使える
n サイト内の共通メニュー、ECサイトのカートなど複数の
ページに共通する部品を表現するのに便利
// 普通のPageObjectのような感覚でModuleを実装
class CommonMenuModule extends Module {
static content = {
linkHome { $(“#home”) }
linkLogout { $(“#logout”) }
}
}
// PageObject内でフィールドとして扱う
class ExamplePage extends Page {
static content = {
commonMenu { module CommonMenu }
}
}
- 24. 24
つまずくかもしれないこと
SSyynnttaaxxの省略に注意
n 省略は便利だが、場合によってはミスを招くこともある
n IDE上での補完に頼りたければ、多少長くなっても型を明記
// 省略あり
to InputPage
userName = “山田 太郎”
mailAddress = “taro.yamada@example.com”
// 省略なし
InputPage page = browser.to InputPage
page.userName = “山田 太郎”
page.mailAddress = “taro.yamada@example.com”
InputPageクラスのフィールド・メソッドが補完される
- 25. 25
つまずくかもしれないこと
SSyynnttaaxxの省略に注意
n Implicit Assertionの使い方に注意
// assertを省略しても大丈夫なケース
$(“p#message”).text() == “MESSAGE”
waitFor { $(“p#message”).text() == “MESSAGE” }
// assertを省略できないケース
if (/** 条件 */) {
assert $(“p#message”).text() == “MESSAGE”
}
n そもそも下の書き方(ケース内で分岐)は微妙
n どうしても避けられないなら全部にassertを入れる
- 26. 26
つまずくかもしれないこと
PPaaggeeOObbjjeeccttの作り方に注意
n getter/setterを作らなくても動かせるので、ついつい生の
処理を書いてしまいがち
n PageObjectの意味がなくなってしまう
// 悪い例
【PageObject】
static content = {
textLoginId { $(“#login_id”) }
textPassword { $(“#password”) }
buttonLogin { $(“#login”) }
}
【TestCase】
loginPage.textLoginId = “user01”
loginPage.textPassword = “pass01”
buttonLogin.click()
- 27. 27
つまずくかもしれないこと
PPaaggeeOObbjjeeccttの作り方に注意
n 保守性を意識してメソッドを切り分ける
// 良い例
【PageObject】
static content = { /** 略 */ }
void login(String loginId, String password) {
textLoginId = loginId
textPassword = password
buttonLogin.click()
}
【TestCase】
loginPage.login(“user01”, “pass01”)
- 28. 28
①失敗時のスクリーンショット取得
+αの工夫
n 前回も話題にした、個人的なこだわり
n Spockのリスナ機能を使って実装
// テスト開始時・終了時・失敗時等のフックを定義できる
class MyListener extends AbstractRunListener {
def void error(ErrorInfo error) {
// スクリーンショットを撮って保存
}
}
// 作成したリスナを登録する
class GlobalSpecException implements IGlobalExtension {
@Override
void visitSpec(SpecInfo specInfo) {
specInfo.addListener(new MyListener())
}
}
- 29. 29
②TTeessttSSuuiitteeの動的生成
+αの工夫
n 自動テストを作り始めの不安定な頃は「Jenkinsで実行した
ときだけテストが失敗する」みたいな事象もある
n 失敗したケースだけを修正前後にサクッと実行できたら便利
// TestSuiteのテンプレート
@RunWith(Suite)
@SuiteClasses([%TEST_CLASS%])
class AllSpecifications {}
n Jenkinsのパラメタで%TEST_CLASS%を置換
- 30. 30
まとめ
n Gebを使うとWebDriverのコードがシンプルになる
n 独自改造も減らすことができる
n Javaの人もそうでない人も
n Gebを使ってみましょう!