2013年2月28日木曜日

Cookieをaddして「続きからはじめる」

テスト作成中, ログインフォームをすっ飛ばして途中からテストを開始する準備がしたかったので

addCookieのちっちゃな落とし穴

ログイン情報を Cookieに持たせているので, 途中からはじめるなら
「addCookieとかあったよなー」
import org.openqa.selenium.Cookie;
  @Before
  public void setUp() throws Exception {
        driver.manage().addCookie(new Cookie(key, value));
なんてぼんやりaddしてたら
org.openqa.selenium.WebDriverException: Could not set the cookie (WARNING: The server did not provide any stacktrace information)
なんて怒られた.
どうやら「まだページ準備できてねーよどのページにCookie作る気だよ!щ(゚Д゚#щ)ゴルァ!」
とかいうことらしい.
なので
import org.openqa.selenium.Cookie;
  @Before
  public void setUp() throws Exception {
        driver.get(適当なページ);
        driver.manage().addCookie(new Cookie(key, value));
と, 何かログイン前に入れるトップページあたりを一度表示してやると addできる.
さすがに Googleトップとかに addしても意味無いけど.

これでaddCookieできますた.




Cookieよくわかんね('A`)

2013年2月27日水曜日

衝突を恐れない/考えない git merge

正直ちゃんとできているのかわからない('A`)

git (もちろんコンソールから)いじっている際, gitpushが ![reject]されたときの一連の流れの覚書
メモメモφ(・ω・ )

Git の 「! [rejection] 」への対処法


※あくまで自動マージで対処できる程度の衝突の際の流れです.
※本物の git初心者向けです. 

とりあえず commitしたものをあげましょう. 最初はmasterと緑なmasterですが…
git push
すると突如発生する ! [reject] から始まるエラー報告. どうやら他からも変更来てるよーってことらしい. ここで慌てると平気で1日つぶすようなパニックに見舞われます. 落ち着くことが大事です. まだここはこわくなーい.

Gitには幸い 自動マージ なるものがあり, 簡単な衝突なら自動でマージしてくれます.
まずはマージの準備
git fetch
だいぶ前にわからないと投げたコマンドを使う衝撃たるや('A`)
コイツはリモートの状態を, 別の作業用ブランチに持ってきてくれるコマンドだったらしい. すなわち先ほどの「他からのコード」をとりあえず別の場所に貰ってきてくれるらしい.
この時点で自分の書いてたコードと, fetchが持ってきてくれたブランチの2種類が存在する.
ここが一番混乱する…(・д・`)
ちなみに実行するとmasterと黄色くなっているかと.
git merge orign/master
これで 自分の書いていたコードのほうに, 持ってきたものを自動マージしてくれる. 問題はここで自動マージできていなかったとき. ファイルに差分を挿入してくれるらしいので, どれがぶつかったか確認して直しちゃいましょう. …改行コードの統一とかができていないとこれがとんでもない地獄になりますΣ(||゚Д゚)ヒィィィィ
マージが全て完了したら, おそらくmasterと緑に戻るかと.
もう一度
git push
すると今度はいってくれるはず.


…人数多いとマージ中とかに pushされるのよね…('A`)オマイラ…



2013年2月26日火曜日

fakeApplicationを使ってテストの初期値を作ろう

Selenium2でテストを続けるうちに出てきた問題.
DBの初期値やらリセットやらどうしよう…

前にjUnitでテストの段階わけのようなことができたので
「じゃぁ@Beforeでデータ入れて@Afterで消せばいっかなー(・з・)」
なんて考えてたら…

fakeApplication()で本体のメソッドを使う

当然本体ではDBにアクセス→参照やら挿入やらやってるもんだから, このメソッドもらえないかなーなんて考えてとりあえずテストの中で呼ぶ

→ There is no started application

…('A`)なんだこれ
どうやらテストは jUnit, 本体は Playの領分らしく, そのままではまたいで呼び出すことはできないらしい. あらめんどくさい. 呼び出せるアプリが起動していないから There is no started application(開始しているアプリはありません) ってことなのか?
そこで見つけたのが fakeApplication()など play.test.Helpersシリーズ. どうやら本体を仮に動かして中のメソッドをいじれるようにしてくれるっぽいという印象だけの理解('A`)
これ使えばわざわざテスト用に起動しなくていいのかも…
import static play.test.Helpers.fakeApplication;
import static play.test.Helpers.running;

running(fakeApplication(), new Runnable() {

      @Override
      public void run() {
         // 初期値作るメソッドやらなんやら
      }
    });
こんな感じ.

ただし今回は, confファイルで使うテーブルを指定しており, これをテスト用のテーブルを使う, と一緒に宣言を変えたいという追加設定.
最初は「別の confを宣言するのか?」なんて考えてまた迷走.
結局たどり着いたのが,
Map<String String> map = new HashMap<String String>();
map.put("confの中で使うテーブルを宣言している項目", "テスト用テーブルの設定");

running(fakeApplication(map), new Runnable() {
// 以下略
Mapを使ってアプリ起動時の application.confを一部書き換えて読み込む方法.
例えば db.default.driverなんていう, 使用する DBの Driverの宣言. これをテスト時には別のものに書き換えたい!なんてときは
map.put("db.default.driver", "別のドライバ")
としてやれば, fakeApplication()で呼ばれるアプリ中では "別のドライバ" を使ってくれる. まぁテスト時だけドライバ変えるのも珍しすぎる気はするけど… いい例えが思いつかなかった…
なお複数 putしていっぱい書き換えることも可能.
そして, 元になるのは通常起動時に読まれる application.confのはず.


そして git嫌い('A`)

OSによる分岐

いろいろいじってたSelenium2
共同開発でいじっていたので中にはMac等Win以外のユーザーもいるわけで.
それはいいのだけど
「chromedriver.exeとかMacじゃ動かないんだけど(・ω・ )っ/凵⌒☆チン」
「chromedriver.shにしてくんね?マダ-?(・ω・  )っ/凵⌒☆チン」

…ぉおぅ('A`)

というわけでOSによって呼び出すchromedriverを変えたいなー, というのが始まり

Java, OSの参照と分岐

chromedriverについてはこちらあたりで. 
特に難しいことはせず, シンプルにif文.
  public static void setChromeProperty() {
    if (SystemUtils.IS_OS_LINUX) {
      // Linux用処理
      return;
    }
    if (SystemUtils.IS_OS_MAC) {
      // Mac用処理
      return;
    }
    if (SystemUtils.IS_OS_WINDOWS) {
      // Windows用処理
      return;
    }
  }
ifの中身
SystemUtils
を参照する.
わりとわかりやすい名前で助かります.∩( ・ω・)∩

OSを判定し booleanが返ってくるのでそのまま ifに入れられるのもわかりやすい.

これだけ.

ちなみにこの SystemUtils. 結構細かいとこまで見てくれているらしく.
SystemUtils.IS_OS_WINDOWS_95
SystemUtils.IS_OS_WINDOWS_98
SystemUtils.IS_OS_WINDOWS_2000
SystemUtils.IS_OS_WINDOWS_ME
SystemUtils.IS_OS_WINDOWS_XP
などOSのバージョンまで見てくれたり.





…ここまでするアプリ作る予定は無いけどネ(・ω・`)

2013年2月25日月曜日

By.xpath中心のメモ

Selenium2でテスト作成時, 嫌でも使わなければならないものが findElement(By).
このByについてメモメモφ(・ω・ )

Byの指定

WebDriver.findElementは今開いているページからその引数で指定した要素( WebElement)を返すメソッド. なのでこの引数を正しく指定しないとエラーに泣くことになる.


By.id("id")
そのままidで要素を探す. なので必ずひとつで返るはず. 安定感は抜群.
By.className("class")
classで探すときは .class()ではなくこれ. っていうか .class()なんてない. 入力補完を使っていればまず無いけど, .id()等で考えが固まっているとつまらないミスでモニターとにらめっこすることになる.
By.name("name")
nameで探す. id以外は複数返る恐れがあるので注意. 複数あるはずなのに .findElement()で探した場合, ページソースを上から探して最初の要素だけ返ってくる. ちゃんと全部みたいなら
List<webdriver> elements = WebDriver.findElements(By by)
を使いましょう.
By.linkText("text")
ちょっと注意. 名前の通り<a>タグで囲まれたリンクのテキストだけを探す. ボタンの文字なんかは検索対象外なので注意.

By.xpath(String path)
この String pathの部分書き方が今回のメイン. たとえばこんなボタンが html上にあったとする.
<button class="btn" onclick='history.back()'>キャンセル</button>
なんてことは無いキャンセルボタン. ただidが振られておらず, classもありきたりな名前でもしかしたら複数取得されるかもしれない.
これを指定したいときは
WebElement element = driver.findElement(By.xpath("//button[@class='btn' and @onclick='history.back()']"));
となる
// → \\ではないので注意
button[条件] → 探したいのが<button>なのでbutton[条件]. もちろん<input>を探したいなら input[条件]となる.
@class='btn' → そのまま, <button>の中の要素 class="btn"を指す. @が無いとバグるので注意.
and → 複数の条件を設定する際に使う. すなおに and.
@onclick='history.back()' → メソッドだろうとお構いなしに条件に指定できる. まぁ文字列見てるとかなんだろうけど.
以降も and @~で条件をどんどん絞り込める.

これで指定できるはず. 一番いいのは idつけてやれば一意に定まるだろうけど, 自分じゃ修正に手が出せないときなんかはこれで. もちろん条件を増やせば絞り込めるけど, 特に classを複数設定しているような要素の場合, スペースや全半角でも条件がずれるので注意.



読みにくっ('A`)

2013年2月22日金曜日

Play起動時の覚書

シンプルに
play "run 9001"
と Playを runすると, デフォルトの9000ではなく指定したポートでPlayを走らせられる.(この場合 9001番ポート)

[run 指定ポート番号]を "" で囲むのがポイントらしい




それだけ(・ω・`)

参考

Selenium2のテスト時間短縮?

前々回あたりでSelenium2のテストを書き始めたが, 毎回毎回ブラウザを立ち上げては消すのがなんとも時間がかかる.
なのでせめて一つのテストファイルの中ではブラウザの立ち上げ→終了は1回にして, 同じウィンドウを使い回せないかと考えた.
これでいいんだろうか…('A`)


Selenium2のテストの余計な時間の短縮


正直8割 jUnit4による解決

  private static WebDriver driver;

  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
    driver = new FirefoxDriver();
  }

  @Before
  public void setUp() throws Exception {
    driver.get(initUrl);
  }

  @After
  public void tearDown() throws Exception {
    driver.manage().deleteAllCookies();
  }

  @AfterClass
  public static void tearDownAfterClass() throws Exception {
    driver.quit();
  }

Firefox版. 単純にjUnitのアノテーションに頼れば何とかなんじゃね?というだけのお話.
アノテーションのおかげで

@BeforeClass → (@Before → @Test → @After) * n → @AfterClass

という順序で呼ばれるので

ブラウザ起動 → (初期状態作成 → テスト → 事後処理) * n → ブラウザ閉じる

とすればいい.
コード的にも前々回使ったコードがほとんど.
driver.manage().deleteAllCookies();
このメソッドで作られてしまったクッキーを削除しているくらい. これを@Afterで行なうことで各テストで作られたクッキーを削除してやる.
@Beforeのところでテストしたい画面の初期状態を作ってやれば, 一つのテストファイル中は同じウィンドウを使いまわしてテストができるはず.

これで毎回テストメソッドごとにブラウザ立ち上げては閉じるなんて時間が大幅にカットできる.
実際変更前のテストごとにウィンドウを開く方法だと6分かかっていたテストも, 3分強程度まで短縮できている.
せいぜい30~40程度ののテストでこれなのだからさらにテストが増えたときの差は大きいはず!
+(・ω・0)*



どうみてもSelenium2の問題ではありません. 本当にありがとうございましたorz

AWS CDKで立てたEC2インスタンスのTimeZoneとかいじりたかった話

EC2を立てることはできたけど、立てたインスタンスは UTCのままだし設定ファイルとかいちいちscpしてくるのはダルい。 当初UserDataでなんとかしようとしたものの、「書く量がヤバいしメンテしにくい」と悩んでいたところ見かけたのが  AWS::CloudFormation:...