【Java】Selenide+ChromeDriverでサクッと統合テスト入門<2020年5月更新>


はじめに

アプリケーションの機能を開発したら他の機能とうまく連動するか、どんな挙動か調べるために統合テスト(結合テスト)やりますよね。
今回はJavaで開発したWebアプリケーションの簡単な統合テストを目視じゃなくて、自動化しちゃおう(当たり前か)ということでSelenide+ChromeDriverを使ったハンズオンをやろうと思います。

※本格的にテストやるならMockitoなど使ってMock呼んでテストする方がいいです。

開発環境

macOS Catalina 10.15.4
IntelliJ IDEA 2018.3.6
Google Chrome 81.0.4044.138
Selenide 5.2.2
aShot 1.5.3

準備

使うライブラリをpom.xmlに記述します。

pom.xml

<dependency>
    <groupId>com.codeborne</groupId>
    <artifactId>selenide</artifactId>
    <version>5.2.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>ru.yandex.qatools.ashot</groupId>
    <artifactId>ashot</artifactId>
    <version>1.5.3</version>
</dependency>

次にChromeDriverを使うためにドライバをダウンロードします。(以下リンク)
https://chromedriver.chromium.org

  1. Downloadsをクリック
  2. Chromeのバージョンに合わせてドライバを選択(今回は81.0.4044.138)
  3. MacOSならmac64.zipを選択しダウンロード後、任意の場所に格納(あとで使うのでパスを覚えておく

基本設定

・Chromeドライバのパスの設定
・ChromeDriverインスタンスの生成
これでSelenideを用いたChromeの自動操作が可能になります。

System.setProperty("webdriver.chrome.driver", "<ドライバのパス>/chromedriver");
WebDriver webDriver = new ChromeDriver();

最終行にclose()を書くことでウィンドウを閉じます。

webDriver().close();

基本操作

以下、テストに必要な操作の中から、基本的なものを説明します。

リンクに遷移

webDriver.get("https://hoge.com/");

もう一つメソッドがあります。

webDriver.navigate().to("https://hoge.com/");

【補足】
get()とnavigate().to()はほとんど同じメソッドだと思ってもらって構いません。両者の違いは、SPA(シングルページアプリケーション)を操作する際に出てきます。SPA内ではget()がページを更新して遷移するのに対し、navigate().to()はページを更新せずに遷移します。get()はブラウザ履歴やcookieを保持せず、navigate().toは保持します。SPAではnavigate().to()の方がより人間が操作してるのに近いテストを実施できるといえます。

戻る・進む

戻る

webDriver.navigate().back();

進む

webDriver.navigate().forward();

更新

更新

webDriver.navigate().refresh();

要素の取得

HTMLのid要素を取得

webDriver.findElement(By.id("hoge"));

class要素を指定できたりもしますが、取得結果が一意にならないことが多いのでid取得がおすすめです。

ボタンのクリック

ボタンのHTMLのid要素を取得し、クリック

webDriver.findElement(By.id("hoge")).click();

フォームの入力

フォームのHTMLのid要素を取得し、sendkeys()で入力

webDriver.findElement(By.id("hoge")).sendKeys("ほげほげ");

挙動は実際に画面に入力しているかのように一文字一文字入力されていきます。

フォームに入力されている値の消去

フォームのHTMLのid要素を取得し、clear()で消去

webDriver.findElement(By.id("hoge")).clear();

値の更新処理で既存の入力内容を消去したい場合に便利です。

スクリーンショットの撮影

一行目で全画面をスクショできるようにページサイズを最小化しています。最小化しないとChromeは自動でウィンドウサイズを調整してしまうので、画面全体がうまく写りません。三行目で画像のパスを指定しています。


webDriver.manage().window().setPosition(new Point(-2000, 0));

Screenshot screenshot = new AShot()
        .shootingStrategy(ShootingStrategies.viewportPasting(100))
        .takeScreenshot(webDriver);

ImageIO.write(screenshot.getImage(), "PNG", new File("<画像保存場所のパス>/<画像名>.png"));

(おまけ)統合テストコードの例

【テストシナリオ】

  1. hogeアプリケーションのログイン画面にアクセスする
  2. 管理者ユーザのメールアドレスとパスワードをフォームに入力
  3. ログインボタンをクリック
  4. 投稿リストの投稿1の編集ボタンをクリック
  5. フォームの投稿名を消去
  6. 投稿名に投稿2と入力
  7. 更新ボタンをクリック
  8. 更新完了後の画面をスクリーンショット

System.setProperty("webdriver.chrome.driver", "hoge/chromedriver");
WebDriver webDriver = new ChromeDriver();

webDriver.get("https://hoge.com/home");
webDriver.findElement(By.id("email")).sendKeys("[email protected]");
webDriver.findElement(By.id("password")).sendKeys("pass");
webDriver.findElement(By.id("loginButton")).click();
webDriver.navigate().to("https://hoge.com/edit?topicId=1");
webDriver.findElement(By.id("topicName")).clear();
webDriver.findElement(By.id("topicName")).sendKey("投稿2");
webDriver.findElement(By.id("updateButton")).click();
webDriver.manage().window().setPosition(new Point(-2000, 0));
Screenshot screenshot = new AShot()
    .shootingStrategy(ShootingStrategies.viewportPasting(100))
    .takeScreenshot(webDriver);
ImageIO.write(screenshot.getImage(), "PNG", new File("hoge/screenshot.png"));

webDriver.close();

おわりに

selenideで検索してもJavaじゃなくてPythonの情報が出てきちゃうのでまとめてみました。
統合テストの例は想像上のwebアプリケーションの想像上のテストなのであしからず。
ありがとうございました。

参考

Difference between webdriver.get() and webdriver.navigate()
Seleniumクイックリファレンス