<!-- markdown -->

# 趣旨
画面操作を伴う自動テストのコツを思い出しやすくするためメモしておく

テストコードに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のツール誰か作ってほしい

## テストクラスの基本構造 [#basic_structure]
### アノテーション
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    - ランダムポートでSpringBootアプリケーションを起動
    @TestPropertySource
    - テスト用のプロパティを設定

### 必要なフィールド
    @LocalServerPort
    - SpringBootが割り当てたポート番号を取得
    WebDriver
    - Seleniumのブラウザ操作用インスタンス
    WebDriverWait
    - 要素の待機処理用

## Page Objectパターン [#page_object]
画面操作をカプセル化するためのパターン
    - 各画面の操作をクラスとして分離
    - テストコードの可読性と保守性が向上

### 実装例

    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);
        }
    }

## テスト実装のポイント [#test_implementation]
### セットアップ処理 [#setup_process]
    @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")));

## テスト実行の設定 [#test_execution]

CIなどで、Seleniumを使った自動テストを自動実行の対象から外したい場合があると思うがその場合の指定をしておく。
### maven-surefire-plugin [#maven_config]
テストの実行制御
    <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`ディレクトリに配置済み

### 実行手順 [#execution_steps]
#1. Chromeブラウザのバージョン確認
    chrome://version にアクセスして確認

#2. テストコマンドの実行

    mvn test -Dtest=テスト対象のクラス名 -Dmaven.compiler.classpath=lib/lombok.jar

## トラブルシューティング
### ChromeDriverのバージョン互換性エラー [#chromedriver_error]
以下の順で対応:
    #1. Chromeブラウザを最新版にアップデート
    #2. キャッシュされたChromeDriverを削除
    - 削除対象ディレクトリ: ~/.cache/selenium
    #3. テストを再実行

### 自動ダウンロードについて [#auto_download]
    - ChromeDriverは WebDriverManager により自動的にダウンロード
    - ただし、Chromeブラウザのバージョンと互換性が必要

# テスト箇所にブレークポイントを張りたい場合
実行には、VSCodeのフラスコマークのアイコンでデバッグ実行ができるが。。。

# テストの設定についてメモ
# Maven Surefireプラグインでテストが実行されない問題の解決方法

## 問題
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.)

## 原因
- maven-surefire-pluginのバージョンが古い(2.22.2など)
- JUnit 4のテストを実行するための適切な設定がない

## 解決方法
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>

## 設定の説明
- version: 最新バージョン(2025年3月時点では3.5.2)に更新
- includes: テストファイルのパターンを指定
- failIfNoTests: テストが見つからない場合にビルドを失敗させない
- useFile: テスト結果をコンソールに直接出力
- testFailureIgnore: テスト失敗時もビルドを続行
- dependencies: JUnit 4用の依存関係(surefire-junit4)を追加

## テスト実行コマンド
特定のテストメソッドを実行する場合:
    mvn test "-Dtest=クラス名#メソッド名"

例:
    mvn test "-Dtest=xxx.SimpleTest#testAlwaysPass"

全てのテストを実行する場合:
    mvn test

## 注意点
- コマンドラインでパラメータを指定する際は、Windowsのcmdでは引用符(")で囲む必要がある
- 文字化けが発生する場合は、UTF-8エンコーディングを指定する("-Dfile.encoding=UTF-8")

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   最終更新のRSS