There is a delay in updating articles on this site, if you want to see articles about Python + Appium, please follow me over to Testhome. Testerhome.com/topics/2780…

What is Page Object mode

The Page Object pattern is the best test design pattern developed by selenium/ Appium automation test project. It designs each Page as a class containing elements (buttons, input fields, titles, etc.) that need to be used in the Page. A test case can call methods and properties in a class to get the elements of the page that it needs to operate on. When the position of Page elements changes, the Page Object mode can change the attributes of the class without modifying the test case (see Baidu). The Page Object mode is referred to as the PO mode.

Second, what are the advantages of PO mode

  • Reduce the amount of code and maintenance
  • Clear and unambiguous business test processes
  • Separation of page elements, element operations, and page business
  • Less repetitive find Click boilerplate code, and page element changes do not affect test cases
  • Improved readability

Basic implementation logic: operate on an element based on a page to implement a specific function

How to implement PO in Python + Appium

  • Webdrive.Remote(URL) : Connects to the server, configits app parameters, and enables the startup and exit of the app
  • Find_element_by_xxx: Encapsulates element location methods
  • Click /send_keys: Encapsulates the page, manipulates elements, and performs specific functions on specific data
  • Testcase: Encapsulates test cases and combines different functions to achieve a specific service

Four examples,

The following uses PO mode to realize the account and password login of weibo. The environment is as follows:

  • Java version: “1.8.0 comes with _241”
  • Python: 3.7.3
  • Node: v12.19.0
  • Appium: v1.18.3
  • PyCharm: Professional 2020.2
  • Weibo: v10.11.3
  • Test framework: PyTest

PO mode

Framework:

1. Init. py file – app parameter configuration to realize app startup and exit

# This class is used to open and exit the app
from appium import webdriver
from page.login_page import LoginPage

class AppStart:
    Declare the driver object
    driver: webdriver = None

    Using the classMethod method, you can directly call the properties and functions of a class
    @classmethod
    def start(cls) :
        caps = {
		"platformName": "Android"."deviceName": "U4AIUKFAL7W4MJLR"."platforVersion": "9"."appPackage": "com.sina.weibo"."appActivity": "com.sina.weibo.SplashActivity"."autoGrantPermissions": "true"."automationName": "UiAutomator2"
                }

        cls.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
        cls.driver.implicitly_wait(20)
        return LoginPage(cls.driver)

    # exit the app
    @classmethod
    def quit(cls) :
        cls.driver.quit()
Copy the code

Note: The specific parameters set in the above code can be found in the previous blog, the blog address is: juejin.cn/post/690088…

2. Base_page.py file – Base class used to encapsulate element location operations

Base class that encapsulates element positioning operations
from selenium.webdriver.remote.webdriver import WebDriver

class BasePage:
    The driver type is WebDriver
    def __init__(self, driver: WebDriver) :
        self.driver = driver

    Locate by id
    def find_element(self, locator) :
        try:
	    # single element location, obtain the location of a single element
            return self.driver.find_element(*locator)
        except:
	    # Multiple elements with the same ID are located, and the obtained is a list. The specific location of a certain element can be queried using the list
            return self.driver.find_elements(*locator)

    Position by xpath
    def find_xpath(self, locator) :
        try:
	    # single element location, obtain the location of a single element
            return self.driver.find_element_by_xpath(locator)
        except:
	    The position of a specific element can be queried using the list. (xpath is a unique location, and generally does not need to use this method.)
            return self.driver.find_elements(locator)

    Locate by className
    def find_classname(self, *locator) :
	# className location is rarely used. It is generally used when id location and xpath location cannot be used. The obtained is a list, and the location of a specific element can be queried using the list
        return self.driver.find_elements_by_class_name(*locator)
Copy the code

Note:

* Locator: Indicates that the number of parameters passed is not fixed. One or more parameter locator can be passed: Indicates that the number of parameters passed is fixed. At least two elements are passed

3. Loge_page.py file – Welcome page action

# Welcome page related operations
from appium import webdriver
from selenium.webdriver.common.by import By
from page.account_login_page import AccountLoginPage
from page.base_page import BasePage

Inherit the BasePage class
class LoginPage(BasePage) :
    Declare the driver variable
    driver: webdriver = None
    # Agree button for privacy policy (find elements according to xpath)
    _btn_agree = "/hierarchy/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.LinearLayout /android.widget.LinearLayout[2]/android.widget.LinearLayout/android.widget.TextView"
   	# account password login button (find elements by ID)
    _btn_account_pwd = (By.ID, "com.sina.weibo:id/tv_for_psw_login")

    Enter the account and password login page
    def enter_account_login(self) :
	Call the xpath element location method and click the Privacy Policy agree button
        self.find_xpath(self._btn_agree).click()
	# Call the id element location method to enter the account password login page
        self.find_element(self._btn_account_pwd).click()
        return AccountLoginPage(self.driver)
Copy the code

4. Account_login_page. py – Account and password Operations performed on the login page include setting the account and password

# Account password login page related operations
import time
from selenium.webdriver.common.by import By
from page.base_page import BasePage

Inherit the BasePage class
class AccountLoginPage(BasePage) :
    # Account input box
    _et_account = (By.ID, "com.sina.weibo:id/et_pws_username")
    # Password input box
    _et_pwd = (By.ID, "com.sina.weibo:id/et_pwd")
    # login button
    _btn_login = (By.ID, "com.sina.weibo:id/bn_pws_Login")
    The content of the pop-up box (bottom marked 0), cancel button (bottom marked 2), pop-up register now button or login button of international mobile number (bottom marked 4)
    _tv_bounced_context = "android.widget.TextView"

    Enter the account function
    def input_account(self, account) :
	# Empty the account input box
        self.find_element(self._et_account).clear()
	# Enter the content in the account input box
        self.find_element(self._et_account).send_keys(account)

    Enter the password function
    def input_pwd(self, pwd) :
	# Clear the password input field
        self.find_element(self._et_pwd).clear()
	Enter the content in the password input box
        self.find_element(self._et_pwd).send_keys(pwd)

    Enter the account and password functions
    def input_account_pwd(self, account, pwd) :
	Call the input account function
        self.input_account(account)
	Call the input password function
        self.input_pwd(pwd)
	Click login password
        self.find_element(self._btn_login).click()

    # Enter the wrong format of the mobile phone number to get the pop-up content function
    def get_bounced_context(self) :
	Store the same className element in the list according to className location
        bounced = self.find_classname(self._tv_bounced_context)
	The contents of the pop-up box are the first in the list, the following table of the list starts from 0, and the contents of the pop-up box are defined as the text attribute
        bounced_context = bounced[0].text
        time.sleep(1)
	Enter the account password and click the register button. The position of the button is the third in the list, so the subscript is 2
        bounced[2].click()
	Return the contents of the popbox so that the contents can be retrieved when the function is called later
        return bounced_context
Copy the code

5. Account_login_testcase. py file – Log in to the testcase using the account and password

Test case for logging in with mobile phone account password
from common.init import AppStart

class TestAccountLogin:
	# initialization
    def setup(self) :
        self.accountloginpage = AppStart.start().enter_account_login()

    Enter the wrong account format
    def test_error_format_account(self) :
	# Set the input account and password
        account = "123123231321313"
        pwd = "asdfgh"
	Call the input account password function
        self.accountloginpage.input_account_pwd(account, pwd)
	Use assertions to determine whether the actual result agrees with the expected result
        assert self.accountloginpage.get_bounced_context() == "There is something wrong with the mobile phone format. If it is not a Chinese mainland mobile phone number, please click on international mobile login."

	# exit the app
    def tearwodn(self) :
        AppStart.quit()
Copy the code