2014年1月10日金曜日

SeleniumでJavaのテストコードを書く方法

私のおすすめの方法を紹介します

SeleniumでUIのテストを作成するときに個人的に一番大変だなと思うのがHTML要素の特定です
Selenium的にベストなのはすべての要素にid属性がふられているのがベストなのですが
そんなSeleniumに特化したUIは存在しないと思います
要素を特定するのに最悪は自然言語から検索してそれらを囲う要素を取得するなんてことをしなければならないこともあるのではと思います
今回は基本的な進め方の1つとして私がいつもやっているテストの作り方を紹介します
また今回はGoogleで検索するまでの動作を自動化してみたいと思います

■環境
Mac OSX 10.8.5(Windows環境でも問題なく動作します)
SeleniumIDE 2.5.0
Eclipse Juno(4.2.1)
Java SE 1.7.0_40

■UIテスト作成方法
0. 事前準備
  • SeleniumIDEのインストール
  • Eclipseのインストール(Maven Integration for Eclipse, TestNG for Eclipse プラグインのインストール)
  • Javaのインストール
  • (mavenのインストール)
は事前に済ませておいてください
mavenはなくてもOKです

1. SeleniumIDEでベースとなるテストの作成
  1. SeleniumIDEを起動します
  2. https://www.google.co.jp/ にアクセスします
  3. SeleniumIDEの右上のブラウザの操作記録を取得することができる赤ボタンをクリックし記録を開始します
  4. Googleの検索窓で「モバイルバックエンド」と入力しGoogle検索を押下します(今回は左記の動作を記憶しテストします)
  5. 記録を停止するため先ほどクリックした赤ボタンを押して記録を停止します
  6. 最終的にSeleniumIDE上で以下のようになっていればOKです


テストがうまく動作するかIDE上で確認します
Googleのトップに戻りSeleniumIDEの「現在のテストケースを実行」を押下します(緑色の三角のアイコンです)
ワードが自動で入力され検索結果が表示されればテストが実行されていることになります
IDE上にも問題がある場合はエラーが表示されるのでエラーがないことを確認します

2. テストのエクスポート
先ほど作成したテストをJavaのコードとしてエクスポートします
SeleniumIDEのメニューバーから
ファイル->テストケースをエクスポート->Java TestNG / Remote Control
をクリックします、ファイルの名前をつけて保存するダイアログが出力されますので「UITest.java」名前をつけて適当なフォルダ配下に保存します

おそらくは以下のようなコードが生成されると思いますので
package com.example.tests;

import com.thoughtworks.selenium.*;
import org.testng.annotations.*;
import static org.testng.Assert.*;
import java.util.regex.Pattern;

public class UITest extends SeleneseTestNgHelper {
        @Test public void testUI() throws Exception {
                selenium.open("/");
                selenium.type("id=lst-ib", "モバイルバックエンド");
                selenium.click("name=btnK");
        }
}
以下のようにいきなり変更します
ポイントしてはFirefoxDriverを生成してから要素を特定するようにしているのと
デフォルトで継承されているSeleneseTestNgHelperを継承しないようにしています
あとはtestngの機能を使ってテストの前処理と後処理を追加してあげました
※このあたりは個人的な好みの問題もあるのでSeleneseTestNgHelperを使って記載したい場合はそのままテストコードを使っても問題ないかと思います
package com.example.tests;

import org.openqa.selenium.By;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.testng.annotations.*;

import java.io.IOException;

public class UITest {

        private FirefoxDriver driver;

        @BeforeClass
        public void before() throws IOException {
                FirefoxProfile profile = new FirefoxProfile();
                profile.setAcceptUntrustedCertificates(true);
                driver = new FirefoxDriver(profile);
        }

        @Test
        public void open() {
                driver.get("https://www.google.co.jp");
        }

        @Test(dependsOnMethods={"open"})
        public void testUI() throws Exception {
                driver.findElement(By.id("lst-ib")).sendKeys("モバイルバックエンド");
                driver.findElement(By.name("btnK")).click();
        }

        @AfterClass
        public void after() {
                driver.close();
        }
}
コードが修正できたらeclipseにコードをコピペします
プロジェクトは通常のJavaプロジェクトでも問題ないですが、自分はmavenプロジェクトで作成しました
パッケージ名はSeleniumIDEからエクスポートしたデフォルトの場合com.example.testsになっているのでそれに合わせるといいと思います
mavenプロジェクトで作成した場合は必要なライブラリの定義(testngとselenium)をpom.xmlに記載し、通常のJavaプロジェクトで作成した場合は各種必要なJarファイルを公式サイト等から持ってくる必要があります
最終的にはプロジェクトが以下のような感じになっていればOKです

3. SeleniumIDEによる要素の特定とコード変換
更にテストを追加していきます
その際に今度は要素を特定しつつ直接コードを書いていくことにします
要素の特定方法自体はFirebugを使ったりするなどいろいろな方法があるかとは思いますが今回はSeleniumIDEだけで要素を特定する方法を紹介します

先ほどのGoogle検索から更に検索結果をクリックするテストを追加したいと思います
SeleniumIDEを開いた状態でGoogleの検索結果のページを開きます
SeleniumIDEでブラウザの記録を開始する赤ボタンをクリックします
その状態で検索結果の一番上のリンクをクリックします


するとSeleniumIDEの対象の部分にSeleniumIDEが解釈した要素情報が表示されます


この情報をコードに反映します
今回SeleniumIDEは対象を「link=ニフティクラウド mobile backend: アプリ開発をよりスマートに、スピーディに」と判断しました
これをコードに変換すると
driver.findElement(By.linkText("ニフティクラウド mobile backend: アプリ開発をよりスマートに、スピーディに")).click();
となります
今回、対象に表示されたのは「link=hogehoge...」の形式でしたが他にも「xpath=」や「css=」等が存在します
それぞれソースコードにひもづけることができ
  • xpath= ⇛ driver.findElement(By.xpath("ここに=以降の値を入力する")).click();
  • css= ⇛ driver.findElement(By.cssSelector("ここに=以降の値を入力する")).click();
  • id= ⇛ driver.findElement(By.id("ここに=以降の値を入力する")).click();
  • name= ⇛ driver.findElement(By.name("ここに=以降の値を入力する")).click();
といった感じで紐付けることができます(上記以外でも他にパターンはあるかと思います)
対象に表示されている内容はSeleniumIDEが現在表示しているページ上で一意に特定できる値を表示してくれますのでこれで簡単に一意の要素を特定することができます
ただ、ここで注意が必要なのがSeleniumIDEが一意と判断したのはあくまでも現在表示されているページ内なので動的にページの内容が変わる場合は同じ要素でも一意に特定できる要素が変わってくる場合があるのでそこはプログラム上でうまくカバーしてあげる必要があります
例えばif文を使って要素がなかった場合は他の要素でクリックするようにするなどです

4. 実行
プログラムに反映したらプログラムからテストできるか確かめてみます
今回はtestng形式で記載しているのでeclipseに「TestNG for Eclipse」のプラグインをインストールする必要があります
プラグインがインストールできたらUITest.javaを右クリックし「Run As」->「TestNG Test」をクリックし実行します
ブラウザが立ち上がり検索結果のページをクリックできたら成功です

うまくテストが成功しない場合はThread.sleepを入れてみたりしてください
あとはプログラム側でいかにうまくテストさせるかとなります

紹介は以上となります
あとは3, 4を繰り返し、要素を調べつつコードを作成し実行する感じが簡単なんじゃないかなと思います
ただ、SeleniumIDE上で特定できてもコードからだとうまく実行できないといったケースもあるようなのでその場合はコード側でループを利用しリトライ処理を実装する等の工夫が必要となります
UIのテストは作るのだけでも一苦労ですが、できたときに動いたときは普通の単体テストとはまた別の感覚が味わえるんじゃないかなと思います

0 件のコメント:

コメントを投稿