はじめに

Spring BootにはJUnitとSelenium WebDriverを組み合わせてEnd to Endテストできる機能が組み込まれている。
Selenium部分は通常のJavaを使ったPageObjectパターンで作成するとして、JUnit部分をどのように設定していけばいいかを記載する。

検証version

  • Spring Boot 1.3.5
  • Selenium WebDriver 2.53.0

Annotation設定

Port

試験を実行するときのPortをランダムで決定するように設定する。
決め打ちでもいいが同一端末上で別のアプリが動いていたりすることがあるので、空Portを使用してくれるランダムPort設定のほうがBetter。

設定方法は、クラスに @WebIntegrationTest(randomPort = true) を、フィールドに @Value("${local.server.port}") を付与する。

@Valueはプロパティファイルの値をフィールドに設定してくれる。

実装具体例

@WebIntegrationTest(randomPort = true)
public class IntegrationTest {
}
@Value("${local.server.port}")
int port;

Contextパス

プロパティファイルでアプリのルートURLとなるContextパスを設定している場合、@ValueでContextパスを変数に設定する。

@Value("${server.context-path}")
String context;

JUnit設定

@RunWith(SpringJUnit4ClassRunner.class) をクラスに付与する。

Spring BootのConfig設定

@SpringApplicationConfiguration(classes = Application.class) をクラスに付与することで、通常実行時と同じように起動する。
src/test/resources にapplication.propertiesを置くことで、テスト用プロパティファイルでオーバーライド可能。 application.propertiesでDBへのデータセット用SQLを設定できるので、テスト用データの管理にSQLを使うことができる。

spring.datasource.schema=schema.sql
spring.datasource.data=data.sql

setupとdestroy

JUnitのsetupとdestroyでは、Selenium WebDriverの起動と終了を管理する。
今回後掲するソースではsetupではFirefoxProfileの設定を行っているが、Seleniumでファイルダウンロードして、その後検証する方法で解説した機能の設定と同じ。ファイルダウンロード機能がないアプリケーションであれば不要となる。

ソース

import static org.junit.Assert.*;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import lombok.SneakyThrows;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebIntegrationTest(randomPort = true)
public class IntegrationTest {
    @Value("${local.server.port}")
    int port;

    @Value("${server.context-path}")
    String context;

    WebDriver driver;

    Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), "seleniumtest", Long.toString(System.currentTimeMillis()));

    @SneakyThrows(IOException.class)
    @Before
    public void setup() {
        Files.createDirectories(tempDir);
        FirefoxProfile profile = new FirefoxProfile();
        profile.setPreference("browser.download.folderList", 2);
        profile.setPreference("browser.download.dir", tempDir.toString());
        profile.setPreference("browser.download.useDownloadDir", true);
        profile.setPreference("browser.helperApps.neverAsk.saveToDisk", "text/html, text/plain, application/vnd.ms-excel, text/csv, application/zip, text/comma-separated-values, application/octet-stream");
        driver = new FirefoxDriver(profile);
    }

    @After
    public void destroy() {
        if (driver != null) {
            driver.quit();
        }
    }

    @Test
    public void EndToEndシナリオ() {
        LoginPage loginPage = LoginPage.to(driver, port, context);
        MainPage mainPage = loginPage.login("user1", "password1", MainPage.class);

        // エラーパターン
        mainPage.download();
        assertEquals("このフィールドは必須です。", mainPage.getResultError().getText());
        ・・・略
    }
}