Seleniumを使ってテスト自動化。[第4回 応用編. Seleniumでテストシナリオを作成する際に注意するポイント with Java]
Seleniumを使用してのテスト自動化。第4回目からは応用編となります。これまでは「Seleniumを使ってテストしてみようかな」という初心者を対象としていましたが、今回からはすでにSeleniumをご存知の方やさらに知見を深めたい方を対象としています。基本的に本シリーズはプログラミング言語としてJavaを使用して説明していきます。
応用編として今回は、Seleniumでテストシナリオを作成する際によくあるトラブルの解決手順について、そして次回はSeleniumを利用したテストツールをさらに発展させるためのスキル、知識について紹介します。
目次
応用編. エレメント操作に関するトラブル回避方法
前回、基本編で「Seleniumでテストを自動化するということはロケータを利用して各エレメントを操作することの組み合わせです。」と説明しました。また、例としてFacebookのログイン動作は以下のように記述できることも紹介しました。
//FacebookのWebサイトを表示 driver.get("http://facebook.com"); //mail address入力(ロケータとしてidを利用) driver.findElement(By.id("email")).sendKeys("testid@callcenter-trend.com"); //パスワード入力(ロケータとしてnameを利用) driver.findElement(By.name("pass")).sendKeys("passworddesu"); //ログインボタンクリック(ロケータとしてxpathを利用) driver.findElement(By.xpath("//*[@id='Login']")).click();
しかしながら、実際にSeleniumを使ってコーディングして、いざプログラムを動かしてみると、「エレメントがうまく取得できない、操作できない」というトラブルに遭遇します。
これは当たり前です。WebサイトはあなたのSelenimプログラムがうまく動作するために作られているわけではありません。あくまでもユーザーがブラウザを操作することを前提に作成されています。そのため、各Webサイトにはそれぞれいわゆる「クセ」があるため、一般的にseleniumで操作する際はWebサイト毎に色々と工夫を凝らす必要があります。
ここではその「クセ」の正体と解消方法についてみていきます。
1. エレメントは存在するが操作できない場合
代表的なものに”element not interactable” というExceptionが発生し、エレメントが操作できないケースがあります。
<原因>
これはそのエラーメッセージの通り、エレメントがまだ使用できる状態ではないが、Seleniumによって操作しようとすると発生します。
例えば、実際のユーザが以下のアクションをブラウザで行うことについて考えていきましょう。
1.マウスをテキストボックス上に持っていく(Hover) -> 2. クリック -> 3. 書き込み
実際に1と2の動作がないとこのテキストボックスが書込可にならない場合、Seleniumで次のようにいきなりテキストボックスに書き込みを行おうとすると上記”element not interactable” というExceptionが発生して失敗してしまいます。
driver.findElement(By.id("name")).sendKeys("Test Name");
<解決方法>
以下のようにアクションを利用してSeleniumでも動作1-3をきちんとシュミレートさせる必要があります。Actionsクラスを使用することにより一連の複数の動作を実行できます。
Actions action = new Actions(driver); WebElement nametxt = driver.findElement(By.id("name")); action.moveToElement(nametxt).click().sendKeys("Test Name").perform();
3行目において、「テキストボックスに移動->クリック->入力」を行っています。
2. エレメントは存在するはずだが認識できない場合
こちらは1のケースよりもさらに深刻です。Seleniumを利用してエレメントを操作できないだけではなく、そもそもエレメントの存在を認識できないケースです。代表的なエラーに以下のようなメッセージが出現して、処理が失敗するケースがあります。
- “no such element: Unable to locate element“
- “Javascript error: Failed to execute ‘elementsFromPoint’ on ‘Document’: The provided double value is non-finite.“
<原因>
この種のエラーはAjaxを多用しているWebサイトや、各種フレームワークを利用して作成されたWebサイトをテストする際に多くみられます。またこの傾向は前述したエラーケース1の場合もあてはまります。
これらのWebサイトではフレームワークの機能を利用してDOMを介して動的にエレメントが表示されたり、状態が変化するため、Seleniumを利用してのエレメント操作の難易度が上がります。
<解決方法>
手順1. 前述したエラーケース1の解決方法を試行する。
手順2. 上記手順1を試行したが失敗した場合、フレームの有無をチェックする。
Javascriptとフレームワークを利用してWebサイトが作成されている場合、その表示されているドキュメントにはフレームが使用されている場合があります。この場合、Seleniumはデフォルトの状態ではフレーム内のエレメントを認識することができません。
次の図で解説します。
実際、ブラウザを利用してWebサイトに訪れたユーザーの場合、エレメントであるtextbox A, B, Cを操作することができます。
しかしながらSeleniumの場合、デフォルトの状態ではFrame 1, 2の存在は認識できますが、そのフレームの中にある、textbox B, Cについては認識することができません。
このため、Seleniumを利用してエレメントを操作する場合、明示的にポジションを以下のように移動します。
- textbox Bを操作する場合はポジションをFrame 1に移動します。
- textbox Cを操作する場合はポジションをFrame 2に移動後、さらにFrame 3に移動します。
以下、移動する際のコード例を紹介します。
//デフォルトポジションに移動 driver.switchTo().defaultContent(); //CssSelectorをロケータとしてフレーム内へ移動 driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[id*='frameApp']"))); //フレーム内のエレメントであるメニュー1をクリック Actions action = new Actions(driver); WebElement tablemenu = driver.findElement(By.id("MenuItem_1")); action.moveToElement(tablemenu).click().perform(); //操作完了後、再びデフォルトポジションへ移動 driver.switchTo().defaultContent();
3. 上記の1,2どちらを試してもまだエレメントが操作できない場合
ここまで来ると何らかの理由でSeleniumだけではエレメント操作ができない可能性があります。また、実際はSeleniumを利用して操作できる場合でもその方法を見つけるために時間がかかり、一時的に他の方法で代用する必要がある場合があります。
このような場合に使える方法としては以下のものがあります。
Javascriptを利用する。
Javascriptを利用することにより処理が代用できる場合に有効です。
JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript(Script,Arguments);
Java Robotを利用する。
コチラは最後の手段です。もうSeleniumは関係ありません。お勧めはしませんが、どうしてもSeleniumで操作できない場合、一時的な代用としては有効な場合があります。
一応、マウスを移動してクリックする例を挙げておきます。
Robot robot = new Robot(); robot.mouseMove(500, 350); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
※実際はSeleniumを利用することにより、通常のWeb操作はほぼすべてシミュレートすることができます。Java Robotの使用は参考程度にしてください。