自動テストは次のようにする必要があります-PageObjectデザインパターン

PageObjectとは何ですか?

ページオブジェクトの抽象処理(ページオブジェクトには、ページ要素、ボタンのクリック、テキストボックスの入力、オプションボックスの選択などが含まれます)。このコードは、ページ要素が変更された後のテストスクリプトへの変更量を最小限に抑え、コードの繰り返し使用を最大限にサポートし、テストフレームワークの構造を合理的かつ明確にし、コードをよりモジュール化して冗長性を回避します。過剰なカップリングが高い。

 

PageObjectの特徴は何ですか?

  • ページはPageクラスにカプセル化され、page要素はPageクラスのメンバー要素です。page関数の実装は、Pageクラスのメソッドに配置されます。

  • テストするページ(またはテストするオブジェクト)をログインページなどのクラスにカプセル化し、それをPageクラスと呼びます。Pageクラスには、このページ(またはテスト対象のオブジェクト)のすべての要素(ログインページのURLリンク、ユーザー名/パスワードのテキストボックスの入力、画像確認コードの取得、ログインのクリック)が含まれます。 /登録ボタン)、およびページ固有要素の操作メソッド(シングルステップ操作またはマルチステップ操作、一般的に定義されているクラスメソッド)。

  • 注:このログインページのPageクラスには、ログインページのみが含まれ、通常、他のページ(ログインページを除く)での操作は含まれません。

  • このPageクラスのテストクラスを定義し、テストクラスのPageクラスの各クラスメソッドを呼び出して、自動テストを完了します。つまり、テストコードは、テストされたページのページコードから切り離されます。たとえば、要素の位置の変更、ページレイアウトの変更、対応するPageクラスのコードのみの変更、およびコードの変更など、ページ自体が変更された場合テストクラスのを変更する必要はありません。PageObjectモードは、コードの冗長性を減らし、ビジネスプロセスを明確で読みやすくし、テストコードのメンテナンスのコストを削減します。

 

PageObjectデザインパターンを実装する方法は?

下図に示すように、それはのPageObjectのクラシックなデザインモジュールのフローチャートです。
画像

図からわかるように、テストクラスでは、多くのテストメソッドを定義します。これらのテストメソッドには、ページオブジェクトインスタンスへの呼び出しが含まれます。ページオブジェクトインスタンスは、ページオブジェクトクラスの初期化操作によって生成されます。多くのページすべてのオブジェクトクラスに存在する共通の操作は、ページオブジェクトの基本クラスに抽出されます。

 

このようにして、次のことを実現できます。

  • プロジェクト全体でページ要素の定義は1つだけで、他の定義が呼び出されます(ページ要素が変更された場合は、この場所を変更するだけです)。

  • Pageクラスの一般的な操作は、BasePageクラスにさらに抽出され、コードの冗長性が軽減されます。

 

PageObjectのPythonライブラリ

Pythonには、PageObject専用のPythonライブラリPageObjectsがあります。ページオブジェクトを使用して、PageObjectモードをすばやく実装します。

page_objectsのインストール
Pythonの一般的なインストールコマンド:pip install page_objects

PageObjectログインページの実用例

#从page_objects包中引入PageObject和PageElement模块
from page_objects import PageObject, PageElement

from selenium import webdriver

class LoginPage(PageObject):

        username = PageElement(id_='username')

        password = PageElement(name='password')

        login = PageElement(css='input[type="submit"]')

driver = webdriver.PhantomJS()

driver.get("http://www.baidu.com")

#实例化一个类对象为:page
page = LoginPage(driver)

#给类对象的username属性赋值为:13057891256(相当于手工在登录页面的用户名输入框输入:13057891256)
page.username = '13057891256'

#给类对象的password属性赋值为:test_123(相当于手工在登录页面的密码输入框输入:test_123)
page.password = 'test_123'

#断言登录页面输入的用户名是否是:13057891256
assert page.username.text == '13057891256'

#让类对象点击登录页面的登录按钮(相当于手工在登录页面点击登录按钮)
page.login.click()

上記は、ログインページを使用したPageObjectの簡単な例です。PO(PageObject)モードの知識はそれだけではありません。次に、実際のプロジェクトでのPageObjectデザインモードのベストプラクティスをご覧ください。

 

プロジェクトの戦闘-PageObjectデザインパターンのベストプラクティス

次のディレクトリ構造は、PageObjectデザインパターンを使用した後のテストフレームワーク構造です。

|--APITestPO

    |--pages

        |--ones.py

        |--base_page.py

    |--tests

        |--test_ones.py

        |--__init__.py

    |--common

        |--__init__.py

        |--selenium_action.py

        |--requests_action.py

 

__init__。pyは空のファイルです。

ones.pyファイルには、ページ自体の要素、オブジェクト、および操作のみが含まれ、ブラウザードライバーの初期化、requests.Session()の初期化、ログイン操作などの他の部分は含まれません。

pages /ones.pyファイルの内容は次のとおりです。

from selenium.webdriver.common.by import By

from selenium.webdriver.support.ui import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC

from page_objects import PageObject, PageElement

from pages.base_page import BasePage

class OneAI(BasePage):

    PROJECT_NAME_LOCATOR = '[class="company-title-text"]'

    NEW_PROJECT_LOCATOR = '.ones-btn.ones-btn-primary'

    new_project = PageElement(css=NEW_PROJECT_LOCATOR)

    def __init__(self, login_credential, target_page):

        super().__init__(login_credential, target_page)

    def get_project_name(self):

        try:

            project_name = WebDriverWait(self.driver, 30).until(

                EC.presence_of_element_located((By.CSS_SELECTOR, self.PROJECT_NAME_LOCATOR)))

            return project_name.get_attribute("innerHTML")

        except TimeoutError:

            raise TimeoutError('Run time out')

 

tests /test_ones.pyファイルの内容は次のとおりです。

import pytest

from pages.ones import OneAI

class TestOneAI:

    # 注意:email和密码需要更改成你自己的账户密码

    @pytest.mark.parametrize('login_data, project_name, target_page', [({"password": "wuliangceshizhidaoIsGood", "email": "[email protected]"}, {"project_name":"GOODTEST"}, {"target_page": "https://ones.ai/project/#/home/project"})])

    def test_project_name_txt(self, login_data, project_name, target_page):

        print(login_data)

        one_page = OneAI(login_data, target_page)

        actual_project_name = one_page.get_project_name()

        assert actual_project_name == project_name["project_name"]

ご覧のとおり、テストクラスtest_ones.pyは非常に簡潔になっています。これには、test_project_name_txtという1つのテストメソッドのみが含まれています。この関数は、提供した値(GOODTEST)と同じではなく、取得したプロジェクト名をテストするために使用されます。

テストクラスでは、Pageクラスのさまざまなメソッドへの呼び出しのみを含める必要があり、テストクラスオブジェクトを直接操作してテストクラスに新しい関数を生成することはできないことに注意してください。

Selenium / WebDriverとRequestsの操作をそれぞれselenium_action.pyとrequests_action.pyに分割します。

 

selenium_action.pyファイルの内容は次のとおりです。

from selenium import webdriver

class SeleniumAction(object):

    @staticmethod

    def initial_driver(browser_name='chrome'):

        browser_name = browser_name.lower()

        if browser_name not in {'chrome', 'firefox', 'ff', 'ie'}:

            browser_name = 'chrome'

        if browser_name == 'chrome':

            browser = webdriver.Chrome()

        elif browser_name in ('firefox', 'ff'):

            browser = webdriver.Firefox()

        elif browser_name == 'ie':

            webdriver.Ie()

        browser.maximize_window()

        browser.implicitly_wait(60)

        return browser

    @staticmethod

    def cookie_to_selenium_format(cookie):

        cookie_selenium_mapping = {'path': '', 'secure': '', 'name': '', 'value': '', 'expires': ''}

        cookie_dict = {}

        if getattr(cookie, 'domain_initial_dot'):

            cookie_dict['domain'] = '.' + getattr(cookie, 'domain')

        else:

            cookie_dict['domain'] = getattr(cookie, 'domain')

        for k in list(cookie_selenium_mapping.keys()):

            key = k

            value = getattr(cookie, k)

            cookie_dict[key] = value

        return cookie_dict

selenium_action.pyには、Seleniumのすべての操作が含まれており、将来のブラウザーのすべての操作は、このpyファイルに配置されます。

 

requests_action.pyファイルの内容は次のとおりです。

import json

import traceback

import requests

from requests.packages.urllib3.exceptions import InsecureRequestWarning

# Disable https security warning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

class SharedAPI(object):

    def __init__(self):

        self.s = requests.session()

        self.login_url = 'https://ones.ai/project/api/project/auth/login'

        self.header = {

            "user-agent": "user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",

            "content-type": "application/json"}

    def login(self, login_credential):

        try:

            result = self.s.post(self.login_url, data=json.dumps(login_credential), headers=self.header, verify=False)

            if int(result.status_code) == 200:

                pass

            else:

                raise Exception('login failed')

            return result

        except RuntimeError:

            traceback.print_exc()

    def post_api(self, url, **kwargs):

        return self.s.post(url, **kwargs)

    def get_api(self, url, **kwargs):

        return self.s.get(url, **kwargs)

Requests_action.pyには、リクエストライブラリに対するすべての操作が含まれています。

 

base_page.pyファイルの内容は次のとおりです。

import json

import traceback

import requests

from selenium import webdriver

from page_objects import PageObject, PageElement

from common.requests_action import SharedAPI

from common.selenium_action import SeleniumAction

class BasePage(PageObject):

    def __init__(self, login_credential, target_page):

        self.api_driver = SharedAPI()

        self.loginResult = self.api_driver.login(login_credential)

        self.driver = SeleniumAction.initial_driver()

        self._api_login(login_credential, target_page)

    def _api_login(self, login_credential, target_page):

        target_url = json.loads(json.dumps(target_page))

        assert json.loads(self.loginResult.text)["user"]["email"].lower() == login_credential["email"]

        all_cookies = self.loginResult.cookies._cookies[".ones.ai"]["/"]

        self.driver.get(target_url["target_page"])

        self.driver.delete_all_cookies()

        for k, v in all_cookies.items():

                self.driver.add_cookie(SeleniumAction.cookie_to_selenium_format(v))

        self.driver.get(target_url["target_page"])

        return self.driver

ご覧のとおり、base_page.pyで、requests.Session()とブラウザーのドライバーを初期化する方法は、SharedAPIクラスとSeleniumActionクラスを呼び出すことです。その後、BasePageクラスには、各Pageクラスで共有できる関数のみが含まれるようになり、無関係な操作は含まれなくなりました。

 

概要

今日の共有では、主に、自動テストの古典的なデザインパターンであるPageObjectデザインパターンを紹介します。PageObjectを通じて、要素の配置、要素、要素の操作の分離を実現できるため、自動テストフレームワークはより再利用可能であり、低コストで維持できます。

PageObjectデザインパターンを通じて、自動テストフレームワークをフレームワークコードやビジネスコードから分離できるかどうかはわかりません。それ以降、私たちのフレームワークは明確に構造化され、理解しやすいように見え、他の同僚の学習コストを削減できます。

[The Way of Infinite Testing]パブリックアカウントへの注目、[リソースの受信]への返信、
Pythonプログラミング学習リソースの乾物、
Python + AppiumフレームワークAPPUI自動化、
Python + Seleniumフレームワーク
WebUI自動化、Python + UnittestフレームワークAPIへようこそオートメーション、

リソースとコードは無料で送信されます〜
記事の下部に公式アカウントのQRコードがあります。WeChatでスキャンしてフォローするだけです。

備考:私の個人公開アカウントが正式に開設され、ビッグデータテスト、機能テスト、テスト開発、APIインターフェイスの自動化、テストの運用と保守、UI自動化テストなどのテストテクノロジーの共有に専念しています。WeChat検索パブリックアカウント:「WuliangThe Way of Testing」、または以下のQRコードをスキャンしてください。

 注意を向けて、一緒に成長しましょう!

おすすめ

転載: blog.csdn.net/weixin_41754309/article/details/113093343