Selenium使ってみたら意外と簡単に始められた

Seleniumは前から「使ってみる」つもりでいましたが、「設定やら準備やら大変そう」と後回しにしてました。
最近、Seleniumを調べる機会があり「あれ？これすぐに始められるんじゃね？」って思い触ってみました。

# 要約

- 作成したコードは[GitHub](https://github.com/kazokmr/seleniumsample)に上げました。
ChromeDriverも含まれているので、Chromeのバージョンが合えばこのまま実行できるはず。
- Selenium自体をテストフレームワークだと思っていたが、実際はブラウザーを制御するツールで、JUnitを使ってテストを書くことがわかった。
- "BDDやATDDのテストケースを作る時"や"探索的テストの操作を再現したい時"に使うと便利。

# 前提

|環境|条件|
|:---:|:---:|
|Selenium|Selenium WebDriver(Selenium2)|
|実行マシン|macOS High Sierra(10.13.5)|
|ブラウザ|Google chrome(67.0.3396.87)|
|プログラム言語|Java|
|テストフレームワーク|JUnit|
|ビルドツール|maven|

※Selenium-Serverは使わない。（ローカルPCを使ってChromeでテストするだけなので）

# 準備

## Selenium Clientのダウンロード

Seleniumを実行するためのライブラリー

<img width="691" alt="スクリーンショット 2018-06-17 6.40.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/160107/6b62af13-4c06-fcda-608d-db7c7fda1b53.png">

- 今回は[Mavenで管理](https://www.seleniumhq.org/download/maven.jsp)した
- 直接追加する場合は、[ダウンロードページ](https://www.seleniumhq.org/download/)からライブラリをダウンロードし、展開したlib/jarをビルドパスに追加する。

## ChromeDriverのダウンロード

Seleniumからブラウザーを制御したり、ブラウザーの状態を取得するためのツール

<img width="700" alt="スクリーンショット 2018-06-17 6.40.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/160107/16af18f9-dd06-59cf-3fc5-fa78611a85e0.png">

ブラウザーごとに対応Driverがあり、今回はChromeで確認した

- [ダウンロードサイト](https://sites.google.com/a/chromium.org/chromedriver/downloads)サイトから使っているChromeのバージョンに合うDriverをダウンロードする。
- （2018.6時点）Chromeは67だったので最新の2.40をダウンロードした
- ダウンロードしたzipファイルを解凍して任意の場所に置く。（今回はMavenプロジェクト配下に置いた）

[ChromeDriver wiki](https://github.com/SeleniumHQ/selenium/wiki/ChromeDriver)

## Mavenプロジェクトの作成

- pom.xmlのdependencyにselenium-javaを指定します
- ダウンロードしたChromeDriverをコピーします

<img width="1177" alt="スクリーンショット 2018-06-16 23.52.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/160107/8824fb79-ec0e-d28c-a2e9-818501399286.png">

# Seleniumを動かしてみた

公式サイトの[Selenium WebDriver](https://www.seleniumhq.org/docs/03_webdriver.jsp#introducing-the-selenium-webdriver-api-by-example)をベースにGoogle検索を実行します
`Thread.sleep(1000)`は、Qiitaに貼る画像をキャプチャーするためのWait用です。

``` SeleniumExample.java
package selenium;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;

public class SeleniumExample {
  
  public static void main(String[] args) throws InterruptedException {
    
    // ChromeDriverまでのパスを設定する
    System.setProperty("webdriver.chrome.driver", "selenium/chromedriver/2.40/chromedriver");
    
    // Chromeドライバーインスタンスを作成する
    WebDriver driver = new ChromeDriver();
    
    // Google.comにアクセスする
    driver.get("https://www.google.com");
    
    // 表示しているページのTitleを出力する
    System.out.println("Page title is: " + driver.getTitle());
    
    Thread.sleep(1000);
    
    // 検索ワード入力エレメントに、検索ワードを渡して、submitする
    WebElement searchElement = driver.findElement(By.name("q"));
    searchElement.sendKeys("Cheese!");
    
    Thread.sleep(1000);
    
    searchElement.submit();
    
    // ページが更新するまで待つ（Timeoutは10秒)
    new WebDriverWait(driver, 10)
        .until((ExpectedCondition<Boolean>) webDriver -> webDriver.getTitle().toLowerCase().startsWith("cheese!"));
    
    // ページ更新後のTitleを出力する
    System.out.println("Page title is: " + driver.getTitle());
    
    Thread.sleep(1000);
    
    // ブラウザーを閉じる
    driver.quit();
  }
}

```

実行するとChromeが立ち上がり検索を実行し、コンソールには検索前後のTitleが出力されたので、Seleniumからブラウザーを制御して情報が取れることが確認できた。  
![Jun-17-2018 08-14-15.gif](https://qiita-image-store.s3.amazonaws.com/0/160107/f3a95095-56b9-028a-e864-ae1ca0545fe4.gif)
(Chromeが自動でアクティブにならないので自分でChromeに切り替えた)

次に、ChromeDriverのサイトにある[Getting started](https://sites.google.com/a/chromium.org/chromedriver/getting-started)のControlling ChromeDriver's lifetime を元にJUnitでテストケースを書いてみた  
(公式サンプルのSelenium-Serverの定義部分は削除しています)

``` ChromeTest.java
package selenium;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;

public class ChromeTest {
  
  private WebDriver webDriver;
  
  @Before
  public void createDriver() {
    System.setProperty("webdriver.chrome.driver", "selenium/chromedriver/2.40/chromedriver");
    webDriver = new ChromeDriver();
  }
  
  @After
  public void quitDriver() {
    webDriver.close();
  }
  
  @Test
  public void testGoogle() {
    webDriver.get("https://www.google.com");
    assertThat(webDriver.getTitle(), is("Google"));
  }
  
  @Test
  public void testGoogleSearch() {
    webDriver.get("https://www.google.com");
    
    WebElement searchElement = webDriver.findElement(By.name("q"));
    searchElement.sendKeys("selenium");
    searchElement.submit();
    
    // ページが更新するまで待つ（Timeoutは10秒)
    new WebDriverWait(webDriver, 10)
        .until((ExpectedCondition<Boolean>) webDriver -> webDriver.getTitle().toLowerCase().startsWith("selenium"));
    
    assertThat(webDriver.getTitle(), is("selenium"));
  }
} 
```
<img width="996" alt="スクリーンショット 2018-06-17 8.45.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/160107/dd17ae4b-6fdf-8f4b-ab5b-2f5d996f5531.png">

testGoogleSearchメソッドが失敗しました。
titleが想定通りでは無かったので、 `assertThat(webDriver.getTitle(), is("selenium"));` を `assertThat(webDriver.getTitle(), is("selenium - Google 検索"));` に変えて再度実行します。

<img width="1001" alt="スクリーンショット 2018-06-17 8.49.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/160107/2ffef3d8-35d3-f39d-fe83-118ed0efea34.png">

無事、成功しました。

# まとめ

Selenium clientとDriverがあれば、比較的簡単にブラウザーを使ったテストコードが書けることがわかりました。

実際には、CIツールと連携する。Selenium-Serverを導入したり、マルチブラウザにも対応すること、テストコードをできる限り簡単に用意する方法などを検討する必要はありますが、少しづつ進めていきたいと思います。