この記事は、 Selenium Advent Calendar 2013 の21日目の記事です。
Seleniumを日々運用していると何回かに1回失敗するようなエラーに遭遇することがよくあります。
今回はそんな気まぐれエラーについて、これまで経験したパターンの主なものをまとめてみました。
また、参考までにそのパターン対して行った対策の一例をあげています。
指定したセレクタが一意になっていない
class属性で指定している場合はよくあるパターン。動的なページは条件によって同じ指定の要素が複数表示されるケースがあり、時と場合によってエラーになる。
対策例
なるべく一意になる指定をする。idを使う、inputのnameを使うなど。
Selenium Advent Calendar 2013 12/1の記事がとても参考になります。
Selenium の locator とうまくつきあうための話
イベントがバインドされてない
クリック動作をテストする場合にクリックする要素にjsのイベントがバインドされる前にSeleniumがテストを実行してしまう。クリックは実行されるがイベントが実行されないので想定通りのテストが行えない。
対策例
バインドされるまでwaitを入れる。例えばある要素がロードされた時にイベントがバンドされていると判定できる場合は、その要素に対してwaitを入れる。最終手段は秒数を指定してsleepさせる。
バインドされている要素と違う要素をクリックしている
例えば以下のようなアイコンを選択させるhtmlがあってそれをクリックするコードを作った場合、js側のclickイベントをバインドしている要素とSeleniumのクリックする要素が合っていないとクリックが反応しないことがある。
<div class="icon tooltip-top">
<a href="#" >
<i class="icon-menu"></i>
</a>
</div>
例)プログラムはa要素にイベントをバインドしているが、Selenium IDEではi要素をclickするコードが生成される。
対策例
これはアプリ側の実装に合わせるしかない。
Selenium IDEを使うとそのような空気を読んだコードは作ってくれない。
運用しやすいコードに仕上げるためにはある程度アプリ側の知識が必要。
要素は存在するが見えてない
DOM上には存在するが実際に表示される前にSeleniumがテストを実行してしまう。あらかじめDOM上に存在させておいてCSSのdisplay属性の指定で表示/非表示を切り替えるようなプログラムを組んだ場合、DOM上の要素を正しく指定してwaitしているつもりでも非表示の状態でテストが実行される場合がある。
対策例
wait.until()に指定するExpectedConditionsのメソッドを正しく使う。
例えばvisibilityOfElementLocated()は表示されるまで待ってくれるが、presenceOfElementLocated()は表示/非表示にかかわらずDOM要素の存在だけしか待たない。
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
wait.until(ExpectedConditions.presenceOfElementLocated(locator));
ドキュメントを参考にして正しくwaitを入れる。
ExpectedConditionsのJavaDoc(英文)
日本語でまとめてくださっているかたがいます。
チラシの裏的備忘録 | Wait.until()で指定できる状態の種類
アニメーションが待てていない
メッセージがフェードインするような処理の場合、そのままSeleniumのテストを実行するとフェードインが終わる前にテストが先に進んでエラーになる。
対策例
メッセージなどの画面に変化が現れる要素があればまずはその要素に対してwaitを入れる。
ただし、前出のvisibilityOfElementLocatedはhightやwidthが0より大きくなるまでしか待たないのでDOM構成やアニメーションのパターンによってはwaitが終わった時点ではまだ想定通りの表示に達していない場合もある。
例)span要素が表示されるまでwaitさせたが、実際にはそのあとゆっくり文字がフェードインするため、wait終了時点ではSeleniumが文字を検出できない
最終手段としてはアプリの実装に合わせてアニメーションにかかる時間のsleepを入れる。
まとめ
Seleniumの運用で最も厄介なのは、アプリの不具合検知以外の原因でエラーになるケースが多々あり、しかも毎回エラーになるのではなく何回かに1回エラーになる現象が起こることです。ローカル環境では正常に動いたのにJenkinsからリモートで実行するとうまく動かなくなるようなケースもよくあります。この現象の原因調査に労力をかけすぎるのは不毛なので、1つ1つベストなケースを探るのではなくいくつかのパターンに応じた対策をあらかじめ決めておいて、まずは深く考えずにいずれかの対策を採用して様子を見るような進め方も運用を続けていくための知恵かもしれません。
一方で、このような何回かに1回しか起こらないエラーでも、ある環境下で正しく動かないのであればそれは不具合という見方もあります。エラーの原因を探ってみると無駄な処理や効率の悪い処理に気づくこともあります。結局は人間が判断するしかないのですが、そのために必要な知識やノウハウをためておくことがSeleniumを賢く運用していくために重要なのではないかと思います。
まだまだ様々なパターンがあると思いますのでノウハウが溜まってきたら続編を書きたいと思います。こんなケースもよくあるよという事例があれば教えてください。