We should all have heard of the PO model when we do automation, so what is the PO model? What is the role of PO model in automation?
PO model
PO is actually: Page Object Model, also known as POM Model. PO is actually a design pattern, which has become popular in automated testing to enhance test maintenance and reduce code duplication. Page object is an object-oriented class, which is used as the interface of the page and the device under test. Then, as long as the tests need to interact with the UI of the page, these tests will use the method of the page object class. The advantage is that if the UI of the page changes, there is no need to change the test itself, just change the code in it. The page object needs to be changed. Subsequently, all changes that support the new UI are in one place. In fact, speaking of low is a sentence: treat each page as a class, separate the element information on the page from the code operation, and then we manage the code and element content later
PO stratification
PO layering means layering our automation code, which can be divided into the following basic levels:
1. Base layer: encapsulate some positioning methods, click, input, sliding and other operations
2. Common layer: get element method, operate element method, get CMD information and other methods
3. Business layer: page element information.
4. Logic layer: some functions, such as login and registration.
5. Data layer: test information storage place
emmm, here is our own understanding. Of course, everyone may have a different understanding of PO layering, and the bosses may share more details than I do here. (share and learn together)
It's quiet and simple here. Take the project to actually introduce the content of PO
First, let's look at how to write test cases before
# coding:utf-8 from appium import webdriver import time import unittest class login(unittest.TestCase): def setUp(self): desired_caps = { 'platformName': 'Android', # Test version 'deviceName': 'emulator-5554', # Device name 'platformVersion': '5.1.1', # System version 'appPackage': 'com.taobao.taobao', #Package name of apk 'appActivity': 'com.ali.user.mobile.login.ui.UserLoginActivity', # launcherActivity of apk 'noReset':True , # Clear cache } self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) def tearDown(self): self.driver.quit() def test01(self): ''' Account password error ''' self.driver.implicitly_wait(40) self.driver.find_element_by_id("com.eboss2.sbs:id/tv_username").send_keys("22222") time.sleep(2) self.driver.find_element_by_id("com.eboss2.sbs:id/tv_password").send_keys("33333333") time.sleep(2) self.driver.find_element_by_id("com.eboss2.sbs:id/btn_login").click() time.sleep(5) x = self.driver.find_element_by_id("com.eboss2.sbs:id/shopName_TextView").text print(x) self.assertEqual(x,'Please enter the correct mobile phone number') if __name__ == '__main__': unittest.main()
I believe that most students will write test cases like this when they write code for the first time
PO model design framework
Someone must ask? What is an automation framework? What are the benefits of an automation framework? Let's not say the answer in this place. Let's write it later
First of all, the framework designed here is listed as a whole and analyzed one by one
appium_python # Target Engineering - case # Case storage test_login.py # Write use cases - common # Common method appium_start.py # Start appium Base.py # Encapsulate basic content dos_cmd.py # cmd execution HTmlTestRunner.py # Report document logger.py # journal read_yaml.py # Read yaml file - config # Page element storage appium.py # login page storage - function # Function point login.py # Login logic - logs # Log storage content - pages # Get page element information login_page.py # Get login element information -report # Report storage place runTest.py # Main function
We need so much content here to complete the above simple operation.
config directory
Here we mainly store some page element information. We also wrote two methods to encapsulate page elements
# appium.yaml LoginPage: dec: Sign in locators: - name: user name type: id value: com.taobao.taobao:id/aliuser_login_mobile_et - name: password type: android value: resourceId("com.taobao.taobao:id/aliuser_register_sms_code_et") - name: Login button type: className value: android.widget.Button
Imagine if we need to read the element information when the element information is available. When reading element information, do you need to list the elements of each page through the method of PO model
common directory
The common directory contains some common parts, such as reading yaml methods, executing cmd contents, and common methods in appium
# read_yaml.py import yaml import os class GetYaml(): def __init__(self,file_path): # Determine whether the file exists if os.path.exists(file_path): self.file_path = file_path else: print('Can't find%s File path'%file_path) self.data = self.read_yaml() def read_yaml(self): with open(self.file_path,'r',encoding='utf-8')as f: p = f.read() return p def get_data(self,key=None): result = yaml.load(self.data,Loader=yaml.FullLoader) if key == None: return result else: return result.get(key) if __name__ == '__main__': read_yaml = GetYaml('E:/appium_python/config/appium.yaml') xx = read_yaml.get_data('LoginPage') print(xx['locators'])
pages directory
Here, each class represents a page to get all the information on the page
# coding:utf-8 from common.Base import BaseApp import os from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from common.loger import Logger path = os.path.dirname(os.path.realpath(__file__)) yaml_path = os.path.join(os.path.join(os.path.dirname(path),'config'),'appium.yaml') class Login_element: def __init__(self,driver): self.log = Logger('element.py') self.driver = driver self.get_element = BaseApp(self.driver) def user_element(self): ''' Get user name element''' self.log.info('Getting user name element information---------------------------------------') element = self.get_element.get_element(yaml_path,'LoginPage')['locators'][0] self.log.info('The user name element information is:%s'%element) return element def password_element(self): ''' Get password element''' self.log.info('Getting user name element information-------------------------------------') element = self.get_element.get_element(yaml_path,'LoginPage')['locators'][1] self.log.info('The password element information is:%s'%element) return element def login_boot(self): ''' Get login button element''' self.log.info('Getting user name element information-------------------------------------') element = self.get_element.get_element(yaml_path,'LoginPage')['locators'][2] self.log.info('The login button element information is:%s'%element) return element def toast(self,message): '''obtain toast information''' toast_loc = ("xpath", ".//*[contains(@text,'%s')]"%message) element = WebDriverWait(self.driver, 30, 0.1).until(EC.presence_of_element_located(toast_loc)).text return element
All the use case elements of the page have been obtained, so we can encapsulate some operation contents, such as login and registration, and then store our data directly
function directory
The function directory represents each test point, for example; Login and registration are all encapsulated separately. When used, they can be called directly
# login.py # coding:utf-8 from pages.login_page2 import Login_element class LoginTest: def __init__(self,driver): self.element = Login_element(driver) self.app = self.element.get_element def login(self,username,password): self.app.send_text(self.element.user_element(),username) self.app.send_text(self.element.password_element(),password) self.app.click(self.element.login_boot())
case directory
case indicates the directory where the test cases are stored
# test_login.py from function.login import LoginTest from common.appium_start import start import unittest import threading import time from common.loger import Logger import warnings warnings.simplefilter("ignore", ResourceWarning) class BaseDriver(unittest.TestCase): @classmethod def setUpClass(cls): '''start-up apk''' cls.log = Logger('anjing') cls.log.info('app Starting') cls.driver = start() cls.log.info('app Start complete') cls.login = LoginTest(cls.driver) def test01(self): '''Account password error''' self.log.info('Case name: wrong account and password, test data: Account Name: 11111, password: 22222,') self.login.login('11111','22222') element= self.login.element.toast('cell-phone number') self.log.info('test01 obtain toast The information is:%s'%element) self.assertEqual(element,'Please enter the correct mobile phone number') def test02(self): '''Account password error 1''' self.log.info('Case name: account password error 1, test data: Account Name: 222, password: 33333,') self.login.login('2222','33333') element= self.login.element.toast('cell-phone number') self.log.info('test02 obtain toast The information is:%s' %element) self.assertEqual(element,'Please enter the correct mobile phone number') @classmethod def tearDownClass(cls): '''sign out APK''' cls.driver.quit() if __name__ == '__main__': t1 = threading.Thread(target=start) t1.start() time.sleep(20) t2 = threading.Thread(target=unittest.main()) t2.start()
logs directory
Logs refers to the place where the printed logs and appium logs are stored during the execution of the use case
report directory
Report indicates the location where the test report is stored
runTest.py file
This main execution file is used to execute all use cases, generate test reports and send emails.
# coding:utf-8 import unittest from common import HTMLTestRunner_cn import time import os import smtplib import threading from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from common.appium_start import start import warnings warnings.simplefilter("ignore", ResourceWarning) # Script path path = os.path.dirname(os.path.realpath(__file__)) # Case use case case_path = os.path.join(path,'case') # Execute the use case and return discover def add_case(rule="test*.py"): '''Load all test cases''' # If the case folder does not exist, one is automatically created if not os.path.exists(case_path):os.mkdir(case_path) # Define the parameters of the discover method discover = unittest.defaultTestLoader.discover(case_path, pattern=rule, top_level_dir=None) return discover # Implementation report def run_case(discover): report_path = os.path.join(path,'report') now = time.strftime("%Y-%m-%d-%H-%M-%S") # Latest report report_abspath = os.path.join(report_path, now+"result.html") # Location of the report rp=open(report_abspath,"wb") runner=HTMLTestRunner_cn.HTMLTestRunner(rp, title=u"Test report", description=u"Implementation of use cases") runner.run(discover) return report_abspath def sen_mail(file_path): smtpserver = 'smtp.163.com' # Send email user name and password user = 'xxxxxx@163.com' password = 'xxxxxx' # Send email sender = 'xxxxxx@163.com' # Receiving mailbox receiver ='821006052@qq.com' #Import Report with open(file_path, "rb") as fp: mail_body = fp.read() msg=MIMEMultipart() body=MIMEText(mail_body,_subtype="html",_charset="utf-8") msg['Subject']=u'Automated test report' msg['from']=sender # Send mail msg['to']=receiver # Take over mail msg.attach(body) att = MIMEText(mail_body, "base64", "utf-8") # Generate attachments att["Content-Type"] = "application/octet-stream" att["Content-Disposition"] = 'attachment; filename="report.html"' # Generate attachment name msg.attach(att) smtp = smtplib.SMTP() smtp.connect(smtpserver) # Connect server smtp.login(user,password) # logon server # Send mail split (',') separator smtp.sendmail(sender, receiver.split(','), msg.as_string()) # close print ("Mail sending") def main(): discover = add_case() # Call execution use case file_path = run_case(discover) # Use case generation Report # sen_mail(file_path) # Send Report if __name__=="__main__": # add_case() t1 = threading.Thread(target=start) t1.start() time.sleep(20) t2 = threading.Thread(target=main) t2.start()
The overall PO model design has been completed. I believe everyone will have an experience. How do you feel that the original method is relatively simple, with less code and simple, but what if there are more test cases? So do you think this method is very simple and has been read.
Here we reply to the previous question? What is the use of an automation framework?
If the automation framework is established, some students with weak code foundation in the group can write test cases according to a template. If the page element or UI changes, we only need to find the corresponding page and element information to modify, so that we can continue to maintain the previous use cases.
So the PO model also accounts for a lot of use, which clearly makes our code more concise and has been read. It is also convenient for maintenance.
Through the above content, I believe you have a simple understanding of the PO model and different layers. You can leave a message here to discuss together and learn more convenient and simple methods
Like and follow ~ ~ keep sharing, join us and learn more. 642830685, get the latest software testing factory interview materials and Python automation, interface and framework building learning materials for free! Technical cattle solve doubts and answer questions, and communicate with peers.