見出し画像

Appiumのテストスクリプトを整理整頓する

前回の記事でiOSのモバイルアプリのテストを自動化できるようにAppiumの学習を進めてきました。
今回はテストスクリプトも長くなってきたのでファイルの整理整頓をしていきたいと思います


1. 整理整頓する目的と利点

Xcodeのプロジェクトファイルも整理整頓されていると後から見た時や他の開発者が見たときにどのファイルで何をしているのか分かりやすいですよね

もちろんテストのスクリプトにもその観点がありますが、
特にテストの観点では以下の観点でファイルを分けるのがよさそうです!

  • 認証情報の保護

    • 試験の性質的にログインに必要なメールアドレスやパスワード、または入力するテキストなどにもセンシティブな情報があったりしてそのような情報は別ファイルで管理することで、Githubのリポジトリなどチームで資材を管理する場所に公開することを防ぐことができます

  • テスト実行時間の短縮

    • 一つのアプリの機能を実行していこうとすると結構長い時間がかかることが考えられます。例えばログインして、ホームスクリーンでいくつかの操作をして出てくる画面のテストをしたいとき、毎回ログインからテストを実行しているとテストにとても時間がかかってしまいます。

2. ファイル構成

以下のようにフォルダー・ファイルを構成します
ファイル名が数字だとPythonが他ファイルにインポートするときに認識できないため数字を冒頭にしないように気をつけます

AppiumTests/
│── pages/
│   ├── __init__.py
│   ├── page_01_login.py 
│   ├── page_02_home.py
│   ├── page_99_base.py
│
│── tests/
│   ├── __init__.py
│   ├── test_01_login.py
│   ├── test_02_home.py
│
│── utils/
│   ├── __init__.py
│   ├── driver_setup.py
│
│── __init__.py
│── config.py
│── test_runner.py
  • pages

    • 各テストスクリプトに対して具体的にどのようなボタンを押すのか、どのようなテキストを入力するのかを定義します

  • tests

    • 実際のテストの流れを定義します。pagesのファイルで具体的な内容は定義されるので、テストの順番やページを読み込む待ち時間を記載することがメインになります

  • utils

    • テストする端末やアプリへのパスなどを定義します

  • __init__.py

    • このファイルはPythonがフォルダーをモジュール (テストに必要なファイル)として認識するために必要になります。内容は適当なコメントだけで問題ありません

  • config.py

    • ログインに必要なメールアドレスやパスワードなどGithubのリポジトリなどで共有したくない情報を管理します

  • test_runner.py

    • testファイルにあるファイルを全て一括して実行するためのファイルです

3. 各ファイルの内容例

pages

from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.common.by import By
from pages.page_99_base import BasePage
import config

class LoginPage(BasePage):
    GOOGLE_LOGIN_BUTTON = (AppiumBy.ACCESSIBILITY_ID, "GIDSignInButton")

    def click_google_login(self):
        self.click(*self.GOOGLE_LOGIN_BUTTON)

    def click_continue_ios_alert(self):
        self.driver.switch_to.alert.accept()

    # configファイルのアカウント名とメールアドレスを使う
    def click_existing_google_account(self):
        self.click(By.XPATH, f'//XCUIElementTypeLink[@name="{config.GOOGLE_ACCOUNT_NAME}"]')

    def click_continue_login_button(self):
        self.click(AppiumBy.ACCESSIBILITY_ID, 'Continue')

tests

テスト例

import sys
import os
import time
import unittest
# utilsとpagesのフォルダーをインポートするためにPathを指定する
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from utils.driver_setup import DriverSetup
from pages.page_01_login import LoginPage

class LoginTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver = DriverSetup().get_driver()
        cls.login_page = LoginPage(cls.driver)

    def test_google_login(self):
        self.login_page.click_google_login()
        time.sleep(1)
        self.login_page.click_continue_ios_alert()
        time.sleep(1)
        self.login_page.click_existing_google_account()
        time.sleep(3)
        self.login_page.click_continue_login_button()
        time.sleep(3)

if __name__ == '__main__':
    unittest.main()

base.py

from selenium.webdriver.common.keys import Keys

class BasePage:
    def __init__(self, driver):
        self.driver = driver

    # UI要素を見つける
    def find_element(self, locator_type, locator):
        return self.driver.find_element(locator_type, locator)

    # UI要素をクリックする
   def click(self, locator_type, locator):
        self.find_element(locator_type, locator).click()

   # 文字をタイプして内容を決定する
    def enter_text(self, locator_type, locator, text):
        self.find_element(locator_type, locator).send_keys(text)
        # and click return
        self.find_element(locator_type, locator).send_keys(Keys.RETURN)

utils

driver_setup.py

from appium import webdriver
from appium.options.ios import XCUITestOptions

class DriverSetup:
    def __init__(self):
        """ Set up desired capabilities for iOS Appium driver """
        options = XCUITestOptions()
        options.platform_name = 'iOS'
        options.platform_version = '18.2'
        options.device_name = 'iPhone 16 Pro'
        options.app = 'path/to/your.app'
        options.automation_name = 'XCUITest'

        self.driver = webdriver.Remote('http://localhost:4723', options=options)

    def get_driver(self):
        return self.driver

config.py

# set as a config file
GOOGLE_ACCOUNT_NAME = "Your Name youraddress@gmail.com"

test_runner.py

import unittest

if __name__ == "__main__":
    test_loader = unittest.TestLoader()
    test_suite = test_loader.discover('tests')
    test_runner = unittest.TextTestRunner()
    test_runner.run(test_suite)

4. テストの実行

terminal内でcd コマンドでテストファイルの階層に移動したあと、テストを実行します

testsフォルダーにあるテストを全て実行する場合

python3 test_runner.py

一つのtestファイルのみ実行する場合

python3 tests/test_01_login.py


いいなと思ったら応援しよう!