Flying Cat Penguin

ゆるゆる仕事、ソフトウェアテスティング関連のことについて綴ります。

Seleniumコードサンプル#3 ページオブジェクトパターン

自動テストのための学習のため、Seleniumコードサンプル(ページオブジェクトパターン)を実施してみます。

以前、読んだpython用の書籍だとすでに試せるサイトが大幅に変わってしまったので、
自分でHTMLファイルを作成して、疑似的に下記の構成を確認しています。
今回は、ページオブジェクトデザインパターンを利用したテストする仕組みを実装してみました。

[画面イメージ]
f:id:dandan_611:20200602172807p:plain

今回は下記の内容を試してみました。

【項目】
・データ駆動テスト
・ページオブジェクトデザインパターン

構成はこんな感じ。
f:id:dandan_611:20200603151032p:plain

書籍もそんなに読み込んでいないのですが…、要はテストケースとテスト対象(画面)の操作を切り分けて、
ベースとなる処理をそれぞれで実装してあげる…というようなものです。

これにより、下記のような効果が期待できます。

  • テスト対象ページが開発者によって変更されたときの変更を最小限に抑えるのに役立つ高レベルの抽象化を作成します。したがって、ページオブジェクトのみを変更し、呼び出しテスト(テストスイートやテストケース)は影響を受けない。
  • 複数のテストケースで共有できる再利用可能なコードの作成できる。
  • テストはより読みやすく、柔軟性があり、保守が容易になる。

[ basepage.py]

from abc import abstractmethod

class BasePage(object):
    """ All page objects inherit from this """
    def __init__(self, driver):
        self.driver = driver

[samplepage.py]

from basepage import BasePage

import time
from selenium import webdriver
from selenium.webdriver.support.ui import Select

class SamplePage(BasePage):
     
    def __init__(self, driver):
        super(SamplePage, self).__init__(driver)

    def submit_data(self, username, password, month):
        # input ID/PASS and push submit botton
        id = self.driver.find_element_by_name("Username")
        id.send_keys(str(username))
        
        password = self.driver.find_element_by_name("Password")
        password.send_keys(str(password))
        
        dropdownlist = self.driver.find_element_by_name("Month")
        month_select_element = Select(dropdownlist)
        month_select_element.select_by_value(str(month))
        
        time.sleep(2)
        
        self.driver.find_element_by_name("Submit").click()

[basetestcase.py](Testcase)

import unittest
from selenium import webdriver
from selenium.webdriver.support.ui import Select

class BaseTestCase(unittest.TestCase):
    def setUp(self): 
        # create a new Chrome session
        self.driver = webdriver.Chrome(executable_path=r'C:/tmp/selenium/chromedriver_win32/chromedriver.exe')
        self.driver.implicitly_wait(30)
        self.driver.maximize_window()
        
        # navigate to page
        self.driver.get("file:///C:/cygwin64/home/XXX/selenium/pageobjectpattern/01_sample.html")

    def tearDown(self):
        # close the browser window
        self.driver.quit()

[sampletestcase.py]

import unittest

from samplepage import SamplePage
from basetestcase import BaseTestCase

from ddt import ddt, data, unpack

@ddt
class SamplePageTestCase(BaseTestCase):

    @data(("odan","odanpass","feb"),("tomohiro","tomohiropass","jul"))
    @unpack
    def test_samplehtml(self, username, password, month):

        sample_page =  SamplePage(self.driver)
        sample_page.submit_data(username, password, month)
        
        # true
        self.assertEqual(10, 10)

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

[sample.html]

<html>
<body>
	<!-- 入力フォーム -->
    <form id="loginForm">
        <label>Enter Username: </label>
        <input type="text" name="Username"/>
        <label>Enter Password: </label>
        <input type="password" name="Password"/>
        
        <!-- ドロップダウンリスト -->
        <select name="Month">
	        <option value="jan">1月</option>
			<option value="feb">2月</option>
			<option value="mar">3月</option>
			<option value="apr">4月</option>
			<option value="may">5月</option>
			<option value="jun">6月</option>
			<option value="jul">7月</option>
			<option value="aug">8月</option>
			<option value="sep">9月</option>
			<option value="oct">10月</option>
			<option value="nov">11月</option>
			<option value="dec">12月</option>
		</select>
		
	<!-- ボタン -->
        <input type="submit" name="Submit"/>
    </form>
    <a href="forgotPassword.html">Forgot Password ?</a>
</body>
</html>

実行すると下記のような出力になります。

$ python samplepagetestcase.py
test_samplehtml_1___odan____odanpass____feb__ (__main__.SamplePageTestCase) ... ok
test_samplehtml_2___tomohiro____tomohiropass____jul__ (__main__.SamplePageTestCase) ... ok

----------------------------------------------------------------------
Ran 2 tests in 26.403s

OK

【まとめ】
ページオブジェクトとを利用したテストを作成することができました。
今回は複数のページを利用していないので全く利点が享受できていない感じですが、実際にはテストケースとページの具体的な操作を切り分けることができるので、画面の操作仕様が変わった際にページオブジェクトを変更、テスト仕様が変わった時にテストケースを変更するなど関心事を分けて作業できるのが利点なのだろうなと感じました。読みやすいのかどうかは、今回はシンプルすぎて確認できませんでした…。

次回は、ページオブジェクトパターンを複数ページのサンプル、もしくは実機を使ったモバイルテストを試してみたいと思います。