- Page Object Modelパターンを利用したSeleniumテストの記述方法についてメモする。
POM(Page Object Model)とは
-
ページをクラスオブジェクトとして扱うブラウザ自動化テストのデザインパターンの一つ。
-
主な概念
- テストクラス
* 対象ページのテストケース。 - ページオブジェクト
* 各Webページオブジェクトを作成することを目的としたクラス。
* テスト用コードとWebページアクセス用コードを分離。 - ロケータ
* ページ要素を取得させる。
- テストクラス
-
利点
- 可読性の高いテストケースを書くことができる。
- 複数のテストケース間で共有できる再利用可能なコードを作ることができる※コード重複を防ぐことができる。
構成
root - TestBase.py
|_ test_GoogleSearch.py
|_ chromedriver.exe
|_ Pages -- google_page.py
|_ Elements - BasePageElement.py
|_ Locators - GoogleSearchPageLocators.py
|_ GoogleSearchResultsPageLocators.py
コード
-
こちらを参考に"Selenium"でGoogle検索するテストケースを記述する。
-
TestBase.py
- WebDriverの起動・停止などテストで共通する処理を集約する。
import unittest from selenium import webdriver # 共通処理を行うベーステストクラス # Webドライバーのオープン/クローズ class TestBase(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.driver.implicitly_wait(10) self.driver.maximize_window() def tearDown(self): if (self.driver != None): print("Cleanup of test environment") self.driver.close() self.driver.quit()
-
test_GoogleSearch.py
- テストケースクラス
import unittest from Pages import google_page from TestBase import TestBase # テストクラス class GoogleSearch(TestBase): # テストケース def test_search_in_google(self): # www.google.comへアクセス self.driver.get("https://www.google.com/") main_page = google_page.MainPage(self.driver) # タイトルに'Google'が含まれているかを確認 assert main_page.is_title_matches(), "Google Title Doesn't Match." # 検索ボックスに"selenium"を入力 main_page.search_text_element = "selenium" # "Google検索"ボタンを押下 main_page.click_search_button() search_results_page = google_page.SearchResultsPage(self.driver) # 検証:検索結果が0件でないこと assert search_results_page.is_results_found(), "No Search Results Found." if __name__ == "__main__": unittest.main()
-
Pages/google_page.py
- ページオブジェクトクラス。
from .Elements.BasePageElement import BasePageElement from .Locators.GoogleSearchPageLocators import GoogleSearchPageLocators from .Locators.GoogleSearchResultsPageLocators import GoogleSearchResultsPageLocators class SearchTextElement(BasePageElement): locator = 'q' class BasePage(object): def __init__(self, driver): self.driver = driver class MainPage(BasePage): search_text_element = SearchTextElement() def is_title_matches(self): return "Google" in self.driver.title def click_search_button(self): element = self.driver.find_element( *GoogleSearchPageLocators.SEARCH_BUTTON) element.click() class SearchResultsPage(BasePage): def is_results_found(self): element = self.driver.find_element( *GoogleSearchResultsPageLocators.SEARCH_RESULT) return element != None
-
Pages/Elements/BasePageElement.py
- ページ要素
from selenium.webdriver.support.ui import WebDriverWait # ページ要素クラス class BasePageElement(object): def __set__(self, obj, value): # 対象ページ要素が読み込まれるまで待機 → 初期化 → 値入力 driver = obj.driver WebDriverWait(driver, 100).until( lambda driver: driver.find_element_by_name(self.locator)) driver.find_element_by_name(self.locator).clear() driver.find_element_by_name(self.locator).send_keys(value) def __get__(self, obj, owner): # 対象ページ要素が読み込まれるまで待機 → 値取得 driver = obj.driver WebDriverWait(driver, 100).until( lambda driver: driver.find_element_by_name(self.locator)) element = driver.find_element_by_name(self.locator) return element.get_attribute("value")
-
Pages/Locators/GoogleSearchPageLocators.py
- Google検索ページ用ロケータ
from selenium.webdriver.common.by import By # Google検索ページ用ロケータクラス class GoogleSearchPageLocators(object): # "Google検索"ボタンのロケータ SEARCH_BUTTON = (By.NAME, 'btnK')
-
Pages/Locators/GoogleSearchResultsPageLocators.py
- Google検索結果ページ用ロケータ
from selenium.webdriver.common.by import By # Google検索結果ページ用ロケータクラス class GoogleSearchResultsPageLocators(object): # 検索結果件数のロケータ SEARCH_RESULT = (By.ID, 'result-stats')
動作確認
python test_GoogleSearch.py
DevTools listening on ws://127.0.0.1:60803/devtools/browser/e2f1274d-85ea-49c2-afdb-e118aea6e63e
Cleanup of test environment
.
----------------------------------------------------------------------
Ran 1 test in 11.892s
OK