Java版アプリケーション自動テストの初期化テンプレート

プロジェクト構成概要

  • ディレクトリ構造: (ドライバの基本設定、グローバル例外処理、エラーショット、レポート自動生成、アプリ共通操作メソッド、ユーティリティクラスのまとめ)
  • パッケージの階層構造: basepageパッケージはアプリ共通操作メソッド、AndroidDriverの基本設定、TestNGの共通実行順序BaseTestを管理し、ドライバを外部に公開。
  • BaseAppクラスには以下の操作を含む: By型でのクリック操作、入力フィールドへのデータ入力、ウィンドウ切り替え、上下左右のスワイプ操作、座標指定でのクリック、ADBコマンド直接実行、戻る/進む/リフレッシュ操作など。他のメソッドは必要に応じて追加可能。

サンプルメソッド:

/**
 * 要素定位でWebElementを取得
 * 
 * @param driver AndroidDriverインスタンス
 * @param elementLocator By型の要素定位
 * @return 見つかった要素
 */
public WebElement findElementWithWait(AndroidDriver driver, By elementLocator) {
    try {
        WebDriverWait wait = new WebDriverWait(driver, 10);
        return wait.until(ExpectedConditions.presenceOfElementLocated(elementLocator));
    } catch (NoSuchElementException | TimeoutException e) {
        System.out.println("===現在のページに該当要素が見つからないため、テストを継続=== ");
    }
    return null;
}

/**
 * 要素クリック処理
 * 
 * @param driver AndroidDriverインスタンス
 * @param elementLocator By型の要素定位
 * @return クリックされた要素
 */
public WebElement performClick(AndroidDriver driver, By elementLocator) {
    try {
        long startTime = DateUtils.getCurrentTimeMillis();
        MobileElement targetElement = (MobileElement) findElementWithWait(driver, elementLocator);
        WebDriverWait wait = new WebDriverWait(driver, 10);
        wait.until(ExpectedConditions.elementToBeClickable(elementLocator));
        if (targetElement.isEnabled()) {
            targetElement.click();
            log.info("クリック処理実行時間(ms):" + (DateUtils.getCurrentTimeMillis() - startTime));
            return targetElement;
        }
    } catch (NoSuchElementException | TimeoutException e) {
        System.out.println("===要素が見つからないためスクリーンショット保存→テスト継続=== ");
        ScreenshotUtil.takeScreenshot(driver);
    }
    return null;
}

/**
 * 入力フィールドへのデータ入力
 * 
 * @param driver AndroidDriverインスタンス
 * @param elementLocator By型の要素定位
 * @param inputText 入力する文字列(複数可)
 * @return 入力フィールド要素
 */
public WebElement inputText(AndroidDriver driver, By elementLocator, CharSequence... inputText) {
    WebElement inputField = findElementWithWait(driver, elementLocator);
    inputField.clear();
    inputField.sendKeys(inputText);
    return inputField;
}

/*===================== スワイプ操作 =====================*/
/**
 * 上方向スワイプ
 */
public void swipeUp(AndroidDriver driver) {
    int screenWidth = driver.manage().window().getSize().width;
    int screenHeight = driver.manage().window().getSize().height;
    new TouchAction(driver)
        .press(PointOption.point(screenWidth / 2, screenHeight * 3 / 4))
        .waitAction(WaitOptions.waitOptions(Duration.ofMillis(500)))
        .moveTo(PointOption.point(screenWidth / 2, screenHeight / 4))
        .release()
        .perform();
}

/**
 * 下方向スワイプ
 */
public void swipeDown(AndroidDriver driver) {
    int screenWidth = driver.manage().window().getSize().width;
    int screenHeight = driver.manage().window().getSize().height;
    new TouchAction(driver)
        .press(PointOption.point(screenWidth / 2, screenHeight / 4))
        .waitAction(WaitOptions.waitOptions(Duration.ofMillis(500)))
        .moveTo(PointOption.point(screenWidth / 2, screenHeight * 3 / 4))
        .release()
        .perform();
}

/*===================== 座標指定クリック =====================*/
/**
 * 座標指定でのタップ操作
 */
public void tapAtCoordinate(AndroidDriver driver, int x, int y) {
    WebDriverWait wait = new WebDriverWait(driver, 5);
    new TouchAction(driver)
        .tap(PointOption.point(x, y))
        .release()
        .perform();
}

/**
 * ADBコマンドでデバイス操作
 */
public void executeADBCommand(AndroidDriver driver, String command) {
    try {
        Process process = Runtime.getRuntime().exec(command);
        WebDriverWait wait = new WebDriverWait(driver, 5);
        process.destroy();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • pageパッケージ(POモード): dataサブパッケージとelementサブパッケージに分離。要素定位と入力データはdataに、操作処理はelementに格納。
  • testcaseパッケージ: ビジネスフローに沿ったテストケースを記述(テストケースのメンテナンスはこのパッケージで実施)
  • resourceパッケージ: chromedriverやスクリーンショット、自動生成レポート(Spring Boot環境で直接アクセス可能)を配置。テストレポートとしてはAllure2が一般的で、GitHubリポジトリにアクセス可能。
  • Allure2レポートの統合: Windows環境では公式サイトからZIPファイルをダウンロードし、環境変数を設定。テスト実行後にallure-resultsフォルダが生成され、以下のコマンドでレポートを開く:
allure serve allure-results

実行フロー例:

  1. testcaseパッケージでテストケースを記述(BaseTestを継承してドライバを取得)
public class SampleTest extends BaseTest {
    SamplePage samplePage = new SamplePage();
    
    @Test
    public void sampleTest() {
        System.out.println(driver);
        samplePage.performAction(driver);
    }
}
  1. pageパッケージのelementサブパッケージで操作クラスを定義(BaseAppを継承)
public class SamplePage extends BaseApp {
    public void performAction(AndroidDriver driver) {
        log.info("要素操作実行");
        clickButton(driver, SampleData.TARGET_ELEMENT);
    }
}
  1. pageパッケージのdataサブパッケージで要素定位情報を定義
public class SampleData {
    public static final By TARGET_ELEMENT = By.id("com.example.app:id/target_view");
}
  1. BaseAppで定義された共通メソッドの使用例
public WebElement clickButton(AndroidDriver driver, By elementLocator) {
    try {
        long startTime = DateUtils.getCurrentTimeMillis();
        MobileElement target = (MobileElement) findElementWithWait(driver, elementLocator);
        WebDriverWait wait = new WebDriverWait(driver, 10);
        wait.until(ExpectedConditions.elementToBeClickable(elementLocator));
        if (target.isEnabled()) {
            target.click();
            log.info("クリック処理実行時間(ms):" + (DateUtils.getCurrentTimeMillis() - startTime));
            return target;
        }
    } catch (Exception e) {
        System.out.println("===要素未検出時の処理→スクリーンショット保存後テスト継続=== ");
        ScreenshotUtil.takeScreenshot(driver);
    }
    return null;
}
  1. TestNGとの統合(Spring Boot環境での実装例)
public class TestRunner {
    @Test
    public void executeAllTests() {
        TestNG testng = new TestNG();
        ExtentTestNGIReporterListener listener = new ExtentTestNGIReporterListener();
        testng.setTestClasses(new Class[] {SampleTest.class});
        testng.addListener(listener);
        testng.run();
    }
}

タグ: AndroidDriver TestNG Allure2 PageObjectModel Java

6月10日 23:44 投稿