Selenium2.x を使ってみた

勉強会のネタとして、Selenium を学習してみた。
仕事でも少しだけ触った(見たことある)程度だったので、いい機会と思い色々調べてみた。

で、色々触ってみたが、はっきりいってかな〜りイイと思った!
今までプレゼン層のテストって、プレゼン層のコンポーネントに対する単体テストしか書いたことなくて、
しかもそのテストって個人的にはほとんど意味を成さないと思っていたから。

理由は以下の通り。

  1. プレゼン層のコンポーネントに対する単体テストを書いても、実際に動かしてみないと分からない部分がある
  2. ほとんど内部構造を意識したテストコード
  3. 保守性が低い(画面からの動作確認をしたら結局テストも直す)

でも、今回触ってみた Selenium は、実際に画面を叩いて動作を確認してくれる。
しかも自動で!!
ここがテストを書くことの良い点!!
自動でバグやデグレを検知できるところが何より大事だと思っているので、
この「実際に画面を叩くい確認する」ということを自動でやってくれるのはスゴイ!
実際コードを書いて動作を見てみたけど、初めてみたときは本当にカルチャーショックかっ!!
って思うくらい新鮮で斬新な動作だった!

ただ、個人的には、仮に画面系のテストに Selenium を導入したからといって、人が実際に画面を叩く必要がゼロになるかと言われると、
そうではないと思う。
だって、画面を叩いてテストするのって、ちゃんと考えればすんごい色んな経路やパターンがあって、
全てをテストするのは現実的では無いと思っている。
だから、従来の単体テストと同様に、その機能を実装した人が不安に思っているところについて、Selenium によるテストを導入する。

これだけでも十分 Selenium を導入することに意味はあるのではないかと思っている。


と、前書きが長くなってしまったが、簡単な導入メモを残しておく。
※以下は Maven プロジェクトを前提に書いていますので悪しからず。

1.Selenium を動かすために必要な依存関係を(pom.xml に)書く

<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>2.24.1</version>
    <scope>test</scope>
</dependency>

2.テストするブラウザのドライバーをダウンロード

とりあえず私が試したブラウザのドライバーは以下から入手可能。
Firefox は試してないです。すいません。)

  1. InternetExproler 用のドライバー
  2. Google Chrome 用のドライバー


3.テストコードを書く

今回はプレゼン層だけに絞ったテストを書いた。
(画面から登録されたデータが DB に入っているよね?の結合テストはまた別途)

まずは IE 向けのテストコード。

/**
 * 著者に関する画面のテスト を InternetExprorer で行うテストクラス。
 *
 */
public class WriterIESeleniumTest {

    private WebDriver driver;

    /**
     * InternetExprorer 用のドライバーを用意。
     */
    @Before
    public void before() {
        driver = new InternetExplorerDriver();
    }

    /**
     * InternetExprorer を閉じる。
     */
    @After
    public void after() {
        driver.quit();
    }

    @BeforeClass
    public static void beforeOnce() {
        System.setProperty(
                InternetExplorerDriverService.IE_DRIVER_EXE_PROPERTY,
                "{ドライバーのパス}/webdriver/IEDriverServer_x64_2.25.3/IEDriverServer.exe");
    }

    @Test
    public void 著者の登録ができること() throws Exception {

        driver.get(Constants.BOOKSHELF_URI);

        // 著者登録画面へ遷移
        driver.findElement(By.linkText("著者 を新規追加")).click();

        // 登録情報を入力
        WebElement element = driver.findElement(By.id("_name_id"));
        element.sendKeys("長澤まさみ");

        // 登録
        element.submit();

        // エラーメッセージがないことを検証
        List<WebElement> errors = driver.findElements(By.id("writer.errors"));
        assertThat(errors.isEmpty(), is(true));
    }
}

続いて Chrome 向けのテストコード。

/**
 * 著者に関する画面のテスト を Chrome で行うテストクラス。
 *
 */
public class WriterChromeSeleniumTest {

    private WebDriver driver;

    /**
     * Google Chrome 用のドライバーを用意。
     */
    @Before
    public void before() {
        driver = new ChromeDriver();
    }

    /**
     * Chrome を閉じる。
     */
    @After
    public void after() {
        driver.quit();
    }

    @BeforeClass
    public static void beforeOnce() {
        System.setProperty(
                ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY,
                "{ドライバーのパス}/webdriver/chromedriver_win_22_0_1203_0b/chromedriver.exe");
    }

    @Test
    public void 著者の登録ができること() throws Exception {

        driver.get(Constants.BOOKSHELF_URI);

        // 著者登録画面へ遷移
        driver.findElement(By.linkText("著者 を新規追加")).click();

        // 登録情報を入力
        WebElement element = driver.findElement(By.id("_name_id"));
        element.sendKeys("長澤まさみ");

        // 登録
        element.submit();

        // エラーメッセージがないことを検証
        List<WebElement> errors = driver.findElements(By.id("writer.errors"));
        assertThat(errors.isEmpty(), is(true));
    }
}

お分かりの通り、上記の IEChrome のテストコードで異なるのは、ドライバーを読み込んでいるところと、
実際にテストするドライバークラスのインスタンスの種類だけ。

テストクラスは全て WebDriver クラス経由でアクセスしているので、
テストメソッド自体は、そのテストがいったいどのブラウザで行われるのかを意識していない。
う〜ん、素晴らしい!!

テストメソッドの内容(検証する内容)が同じで、テストするブラウザだけが違うとなると、
最近覚えた @Theory とかが使えそうな予感。。。
そうすれば、テストクラスをいちいち分けなくても、むにゃむにゃ。。。


ただ、上記で示したサンプルはとっても簡単な画面操作しか行っていないが、
JavaScript などは、ブラウザ依存の関数等もあるので、その辺りを使っている場合のテストをどうするのか?という課題は残るね。

今回は超簡単にですが、Selenium2.x 系を使ったテストを書いてみた。
次は、この Selenium を動かすためにハマッたところなどを書く予定。


現場で使えるJavaライブラリ

現場で使えるJavaライブラリ