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