📘 Vol.9.9：【Struts2】バリデーション処理の単体テスト編 〜 validate()／独自バリデータ／input遷移の検証を網羅的に 〜

### 🧭 はじめに
Struts2 のバリデーション処理は、ユーザー入力の正当性を保つ重要な機能ですが、
そのロジックが複雑になるほど ***テストによる品質担保***が必要不可欠です。

本記事では、以下の観点から「バリデーションの単体テスト方法」を実務ベースで解説します。

---

### ✅ 本記事で扱う内容

- `validate()`メソッドのテスト方法

- 独自バリデータ`（FieldValidator）`の単体テスト

- `input` への遷移確認やエラーメッセージ表示のテスト

- テストパターン設計の実例

---

### 🔍 1. テストパターン設計（実務の流れ）

まず最初に行うのが、「どんな入力パターンをテストすべきか」の ***パターン洗い出し*** です。
これは、仕様書や画面設計書をもとに以下のような観点で整理します。

| 観点     | テスト例                   |
| ------ | ---------------------- |
| 必須チェック | ユーザー名が空                |
| 桁数制限   | ユーザーIDが20文字超           |
| 形式指定   | パスワードが数字だけ／英字だけ        |
| 相関チェック | パスワードと確認用パスワードが一致していない |
| 数値範囲   | 年齢がマイナス値               |

👀 実際のプロジェクトではこのように ***ExcelやPDF形式*** でまとめて整理しています：

📄 [入力値テストケース（ログイン画面）](https://github.com/juehara-crypto/Portfolio_Bulletinboard/blob/master/04.%E5%8D%98%E4%BD%93%E3%83%86%E3%82%B9%E3%83%88%E4%BB%95%E6%A7%98%E6%9B%B8/%E5%8D%98%E4%BD%93%E3%83%86%E3%82%B9%E3%83%88%E3%82%B1%E3%83%BC%E3%82%B9(%E5%85%A5%E5%8A%9B%E5%80%A4%E3%83%86%E3%82%B9%E3%83%88_%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E7%94%BB%E9%9D%A2%E9%96%A2%E9%80%A3).pdf)


---

### 🧪 2. validate() のテスト例（JUnit）

Struts2の Action クラスで `validate()` をオーバーライドしている場合、
JUnit で以下のように単体テスト可能です。

```java
@Test
public void testValidate_emptyFields() {
    LoginAction action = new LoginAction();
    action.setUserId("");
    action.setPassword("");
    
    action.validate();
    
    assertTrue(action.hasFieldErrors());
    assertEquals(2, action.getFieldErrors().size());
    assertTrue(action.getFieldErrors().get("userId").contains("ユーザーIDは必須です"));
}
```

- `hasFieldErrors()` でエラー発生の有無を確認

- `getFieldErrors().get("フィールド名")` で具体的なエラーメッセージ確認

---

### 🧩 3. 独自バリデータ（Custom Validator）のテスト例

`FieldValidatorSupport` を継承したクラスも、テスト可能です。

```java
@Test
public void testCustomValidator() throws ValidationException {
    MyCustomValidator validator = new MyCustomValidator();
    validator.setFieldName("userId");
    validator.setDefaultMessage("不正な形式です");

    ValidatorContextMock context = new ValidatorContextMock();
    validator.setValidatorContext(context);

    // 無効な値
    validator.validate("abc!!");

    assertTrue(context.hasFieldErrors());
}
```

 🛠 MockContext を使うことで、`validate()` 単体をテストできます。

### 🔁 4. input 遷移の検証（ActionProxy 利用）
Struts2 本体の挙動（inputへの遷移や結果判定）も以下のように確認できます。

```java
@Test
public void testLoginAction_inputTransition() throws Exception {
    ActionProxy proxy = getActionProxy("/login");
    LoginAction action = (LoginAction) proxy.getAction();

    action.setUserId(""); // エラー条件
    action.setPassword("test");

    String result = proxy.execute();

    assertEquals("input", result); // inputに遷移すること
    assertTrue(action.hasFieldErrors());
}
```

✔ `ActionProxy` で実行すると、Struts2の結果遷移も含めてテストできます。

---

### 🧱 5. テスト設計のベストプラクティス
複数画面やフォームを扱う場合、テスト構成を以下のように整理しておくと便利です。


```bash
src/test/java/
└── validation/
    ├── BaseValidationTest.java
    ├── LoginValidationTest.java
    ├── UserFormValidationTest.java
    └── CustomValidatorTest.java
```
---

### ✅ まとめ

| 観点              | 内容                             |
| --------------- | ------------------------------ |
| テストパターン設計       | 観点を洗い出し、仕様に沿ったテストケースを作成        |
| validate() のテスト | `hasFieldErrors()` で結果を確認      |
| 独自バリデータの検証      | 単体で `validate()` を呼び出してテスト可能   |
| input 遷移の確認     | `ActionProxy` を使って実際の画面遷移結果を検証 |

Struts2 のバリデーション処理は非常に柔軟である一方、
その動作確認を `パターンごとに丁寧にテスト` することで、
品質と保守性が格段に向上します。

---

### [🧭 次回予告：Vol.9.10](https://qiita.com/juehara-crypto/items/6c042593898aa598cba4)
次回は、***画面側のUX向上編！***

- `<s:fielderror>` の高度な使い方

- エラー時の入力欄装飾（赤枠表示、ツールチップ）

- JavaScriptと連携したリアルタイムバリデーション

バリデーションの「見せ方」 を工夫して、より使いやすいUIを実現していきましょう！

---



### ✨ シリーズまとめ（Vol.9.x バリデーション編）


| 回   | テーマ                                         | 内容の一部紹介                              |
|------|----------------------------------------------|--------------------------------------------|
| [9.1](https://qiita.com/juehara-crypto/items/a67976acd60430fa0da6)  | `validate()`メソッドの基本                    | Struts2標準の入力チェック基礎              |
| [9.2](https://qiita.com/juehara-crypto/items/44fd5012bfbc809d352a)  | `@Validations` アノテーション活用             | 宣言的バリデーション設計                   |
| [9.3](https://qiita.com/juehara-crypto/items/fd6881d2c54de07b3ae4)  | `validation.xml` 外部定義でのバリデーション   | 大規模PJでのメンテナンス性                 |
| [9.4](https://qiita.com/juehara-crypto/items/c82203f583b2712be395)  | `conversion.properties` と型変換              | 日付/数値/Enum変換の実務対応               |
| [9.5](https://qiita.com/juehara-crypto/items/c44fae5980a5c9b40312)  | 入力エラー時のメッセージ制御                  | `addFieldError()` / メッセージキー運用     |
| [9.6](https://qiita.com/juehara-crypto/items/de18b174f1740f9b3646)  | バリデーション共通化                         | 共通部品によるDRY設計                      |
| [9.7](https://qiita.com/juehara-crypto/items/793e85ad47b981d6fbae)  | サーバサイドとクライアントサイドの協調        | jQueryやHTML5との併用戦略                  |
| [9.8](https://qiita.com/juehara-crypto/items/b11017ca621d94599f72)  | 実務シナリオでのバリデーション総仕上げ       | 会員登録/投稿処理などの実例適用           |
| [9.9](https://qiita.com/juehara-crypto/items/6df87d22d07818df5166)  | バリデーション処理の単体テスト編       | validate()／独自バリデータ／input遷移の検証を網羅的に |
| [9.10](https://qiita.com/juehara-crypto/items/6c042593898aa598cba4)  | エラー表示のUIデザイン編        | 視認性・操作性を高める実践テクニック |
| [9.11](https://qiita.com/juehara-crypto/items/7d33c9cd812b37153c12)  | Ajax×バリデーション連携編        | クライアント×サーバーで UX＆保守性を両立するハイブリッド構成 |



---