画面操作を伴う自動テストのコツを思い出しやすくするためメモしておく
テストコードにseleniumの自動操作をいれるが、そうなると、サーバの実行プロセスとは別になり、ブレークポイントで停止させる難易度が跳ね上がる。
ところどころ間違いがあるかもしれないが、どうやっていたか、少し思い出しながらメモを書いていく
はてサーバは別途デバッグ起動しておくんだったかな。。。?
という感じで記憶がやばい、いろいろ試行錯誤してして記憶が混濁してしまった。動いたときに、すぐに成功のコツをメモしないとこうなってしまうんだな。以後気を付けよう
AIがすぐに作ってくれなかったのでやり方のコツをメモしておく
pom.xmlに以下の依存関係を追加する:
selenium-java junit-jupiter webdrivermanager
pomに各jarのバージョン変数を追加
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <lombok.version>1.18.36</lombok.version> <selenium.version>4.18.0</selenium.version> <junit.jupiter.version>5.10.2</junit.jupiter.version> <assertj.version>3.25.3</assertj.version> <webdrivermanager.version>5.7.0</webdrivermanager.version> </properties>
依存をpomに追加
<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>${selenium.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>${junit.jupiter.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>io.github.bonigarcia</groupId> <artifactId>webdrivermanager</artifactId> <version>${webdrivermanager.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.2.1</version> <scope>test</scope> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> <scope>test</scope> </dependency>
これらを設定したら、
mvn dependency:resolve
コマンドを実行
追加するGUIのツール誰か作ってほしい
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) - ランダムポートでSpringBootアプリケーションを起動 @TestPropertySource - テスト用のプロパティを設定
@LocalServerPort - SpringBootが割り当てたポート番号を取得 WebDriver - Seleniumのブラウザ操作用インスタンス WebDriverWait - 要素の待機処理用
画面操作をカプセル化するためのパターン
- 各画面の操作をクラスとして分離 - テストコードの可読性と保守性が向上
public class SearchPage { private WebDriver driver; private WebDriverWait wait; public SearchPage(WebDriver driver, WebDriverWait wait) { this.driver = driver; this.wait = wait; } public DetailPage searchAndOpenDetail(String receptionNo) { // 画面操作のロジック return new DetailPage(driver, wait); } }
@BeforeEach内で実施 - WebDriverManagerでブラウザドライバセットアップ - ブラウザウィンドウの最大化 - ログイン処理
例: 大体同じような処理をすると思うので、よく使う処理をabstractクラスに書いておいて、テストクラスを作るときには、このクラスをextendsするようにすると、記述が簡単になるだろう。
public abstract class BaseSeleniumTest { protected WebDriver driver; protected WebDriverWait wait; protected String originalWindow; @BeforeEach public void setUp() { WebDriverManager.chromedriver().setup(); driver = new ChromeDriver(); wait = new WebDriverWait(driver, Duration.ofSeconds(10)); driver.manage().window().maximize(); // ログインページにアクセス driver.get("http://localhost:8080/xxx/login"); // ログインボタンを見つけてクリック WebElement loginButton = wait.until(ExpectedConditions.presenceOfElementLocated( By.cssSelector(".xxx"))); loginButton.click(); // 管理画面が表示されるまで待機 wait.until(ExpectedConditions.titleContains("タイトル文言など")); // 元のウィンドウハンドルを保存 originalWindow = driver.getWindowHandle(); }
@AfterEach public void tearDown() { // 新しいウィンドウが開いている場合は閉じる Set<String> windows = driver.getWindowHandles(); if (windows.size() > 1) { windows.stream() .filter(handle -> !handle.equals(originalWindow)) .forEach(handle -> { driver.switchTo().window(handle); driver.close(); }); // 元のウィンドウに戻る driver.switchTo().window(originalWindow); } if (driver != null) { driver.quit(); } } }
@AfterEach内で実施 - ブラウザの終了(driver.quit())
WebDriverWait?を使用して要素の表示を待機
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".selector")));
CIなどで、Seleniumを使った自動テストを自動実行の対象から外したい場合があると思うがその場合の指定をしておく。
テストの実行制御
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <excludedGroups>selenium</excludedGroups> </configuration> </plugin>
- Chromeブラウザがインストール済み - アプリケーションが起動済み(http://localhost:8080) - Lombokのjarファイルが`lib`ディレクトリに配置済み
#1. Chromeブラウザのバージョン確認
chrome://version にアクセスして確認
#2. テストコマンドの実行
mvn test -Dtest=テスト対象のクラス名 -Dmaven.compiler.classpath=lib/lombok.jar
以下の順で対応:
#1. Chromeブラウザを最新版にアップデート #2. キャッシュされたChromeDriverを削除 - 削除対象ディレクトリ: ~/.cache/selenium #3. テストを再実行
- ChromeDriverは WebDriverManager により自動的にダウンロード - ただし、Chromeブラウザのバージョンと互換性が必要
実行には、VSCodeのフラスコマークのアイコンでデバッグ実行ができるが。。。
Maven Surefireプラグインでテストを実行しようとすると、以下のようなエラーが発生する場合があります:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test) on project xxx: No tests were executed! (Set -DfailIfNoTests=false to ignore this error.)
pom.xmlに以下の設定を追加します:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.5.2</version> <configuration> <includes> <include>**/*Test.java</include> </includes> <failIfNoTests>false</failIfNoTests> <useFile>false</useFile> <testFailureIgnore>true</testFailureIgnore> </configuration> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit4</artifactId> <version>3.5.2</version> </dependency> </dependencies> </plugin>
特定のテストメソッドを実行する場合:
mvn test "-Dtest=クラス名#メソッド名"
例:
mvn test "-Dtest=xxx.SimpleTest#testAlwaysPass"
全てのテストを実行する場合:
mvn test