appium---PO模型設計

   咱們在作自動化的時候應該都聽過PO模型,那麼什麼是PO模型呢?PO模型在自動化中的做用是什麼呢?html

PO模型

PO其實就是:、Page Object Model,也稱做爲POM模型,PO實際上是一種設計模式,已經在自動化測試中流行起來,以加強測試維護並減小代碼重複。頁面對象是面向對象的類,用做頁面的接口和被測設備。 而後,只要測試須要與該頁面的UI進行交互,這些測試便會使用該頁面對象類的方法,其好處在於,若是頁面的UI發生了更改,則無需更改測試自己,只需更改其中的代碼便可。頁面對象須要更改。 隨後,全部支持該新UI的更改都位於一個位置。其實說到低就是一句話:把每個頁面看成一個類,把頁面上的元素信息和代碼操做分離開,而後方面後面咱們進行管理代碼和元素內容python

PO分層

 PO分層也就是對咱們自動化代碼進行分層具體能夠分爲如下基層android

一、基礎層:封裝一些定位方法,點擊,輸入,滑動等操做web

二、公用層:獲取元素方法,操做元素方法,獲取CMD信息等方法設計模式

三、業務層:頁面元素信息。緩存

四、邏輯層:一些功能,好比登陸,註冊。服務器

五、數據層:測試信息存放地方app

emmm,這裏是安靜這邊自身的瞭解,固然可能每一個人對PO分層的理解不一樣,可能大佬們分的比我這裏更加詳細。(一塊兒分享,共同窗習)框架

這裏安靜簡單拿項目來進行實際介紹下PO內容函數

首先咱們先看之前如何編寫測試用例的

# coding:utf-8
from appium import webdriver
import time
import unittest
class login(unittest.TestCase):
    def setUp(self):
        desired_caps = {
                        'platformName': 'Android',  # 測試版本
                        'deviceName': 'emulator-5554',   # 設備名
                        'platformVersion': '5.1.1', # 系統版本
                        'appPackage': 'com.taobao.taobao', #apk的包名
                       'appActivity': 'com.ali.user.mobile.login.ui.UserLoginActivity', # apk的launcherActivity
                        'noReset':True , # 清除緩存
                        }
        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    def tearDown(self):
        self.driver.quit()
    def test01(self):
        '''
        帳號密碼錯誤
        '''
        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,'請輸入正確的手機號')
if __name__ == '__main__':
    unittest.main()

相信絕大部分的同窗,第一次寫代碼的時候都會這樣寫測試用例

PO模型設計框架

確定有人會問?什麼是自動化框架?自動化框架有什麼好處呢?這個地方咱們先不說答案,咱們後面寫

首先把安靜這邊設計的框架先總體列出來,一個個爲你們分析

appium_python    # 目標工程
    
    - case        # 用例存放
        test_login.py    # 編寫用例

    - common    # 公用方法
        appium_start.py    # 啓動appium
        Base.py    # 封裝基礎內容
        dos_cmd.py    # cmd執行
        HTmlTestRunner.py    # 報告文件
        logger.py    # 日誌
        read_yaml.py    # 讀取yaml文件
    
    - config    # 頁面元素存放
        appium.py    # login頁面存放
        
    - function     # 功能點
        login.py    # 登陸邏輯
        
    - logs    # 日誌存放內容
        
    - pages    # 獲取頁面元素信息
        login_page.py    # 獲取登陸元素信息
        
    -report    # 報告存放地方
        
    runTest.py    # 主函數

咱們這裏須要這麼多內容,才能完成上面的簡單的操做。

config目錄

這裏咱們主要存放一些頁面元素信息,前面也寫了兩種方法進行封裝頁面元素

# appium.yaml
LoginPage: dec: 登陸 locators:
- name: 用戶名 type: id value: com.taobao.taobao:id/aliuser_login_mobile_et - name: 密碼 type: android value: resourceId("com.taobao.taobao:id/aliuser_register_sms_code_et") - name: 登陸按鈕 type: className value: android.widget.Button

想象下,元素信息有了,咱們是否是須要進行讀取元素信息。讀取元素信息的時候,是否是又須要經過PO模型的方法,把每一個頁面的元素都列舉出來

common目錄

common目錄中包含一些公用的部分,好比讀取yaml方法,執行cmd內容,appium中經常使用的方法等操做

# read_yaml.py

import yaml
import os
class   GetYaml():
    def __init__(self,file_path):
        # 判斷文件是否存在
        if os.path.exists(file_path):
            self.file_path = file_path
        else:
            print('沒有找到%s文件路徑'%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目錄

這裏咱們把每一個類中都表明一個頁面,獲取頁面上的全部信息

# 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):
        ''' 獲取用戶名元素'''
        self.log.info('正在獲取用戶名元素信息---------------------------------------')
        element = self.get_element.get_element(yaml_path,'LoginPage')['locators'][0]
        self.log.info('用戶名元素信息爲:%s'%element)
        return element

    def password_element(self):
        ''' 獲取密碼元素'''
        self.log.info('正在獲取用戶名元素信息-------------------------------------')
        element = self.get_element.get_element(yaml_path,'LoginPage')['locators'][1]
        self.log.info('密碼元素信息爲:%s'%element)
        return element

    def login_boot(self):
        ''' 獲取登陸按鈕元素'''
        self.log.info('正在獲取用戶名元素信息-------------------------------------')
        element = self.get_element.get_element(yaml_path,'LoginPage')['locators'][2]
        self.log.info('登陸按鈕元素信息爲:%s'%element)
        return element

    def toast(self,message):
        '''獲取toast信息'''
        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

頁面用例元素都已經所有獲取出來了,那麼咱們能夠經過封裝一些操做內容,好比說登陸,註冊,而後直接把咱們的數據存放進去

function目錄

function目錄表示每一個測試點,例如、;登陸和註冊所有都單獨封裝起來,用的時候,能夠直接進行調用

# 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目錄

case表示存放測試用例的目錄

# 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):
        '''啓動apk'''
        cls.log = Logger('anjing')
        cls.log.info('app啓動中')
        cls.driver = start()
        cls.log.info('app啓動完成')
        cls.login = LoginTest(cls.driver)
    def test01(self):
        '''帳號密碼錯誤'''
        self.log.info('用例名稱:帳號密碼錯誤,測試數據:帳號名:11111,密碼:22222,')
        self.login.login('11111','22222')
        element= self.login.element.toast('手機號')
        self.log.info('test01獲取toast信息爲:%s'%element)
        self.assertEqual(element,'請輸入正確的手機號')

    def test02(self):
        '''帳號密碼錯誤1'''
        self.log.info('用例名稱:帳號密碼錯誤1,測試數據:帳號名:222,密碼:33333,')
        self.login.login('2222','33333')
        element= self.login.element.toast('手機號')
        self.log.info('test02獲取toast信息爲:%s' %element)
        self.assertEqual(element,'請輸入正確的手機號')

    @classmethod
    def tearDownClass(cls):
        '''退出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目錄

logs表示執行用例過程當中,存放本身打印的日誌地方和appium日誌

report目錄

report表示存放測試報告的位置

 

runTest.py文件

這個主執行文件,用來執行全部的用例,生成測試報告,發送郵件。

# 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)
# 腳本路徑
path = os.path.dirname(os.path.realpath(__file__))
# case用例
case_path = os.path.join(path,'case')
# 執行用例 返回discover
def add_case(rule="test*.py"):
    '''加載全部的測試用例'''
    # 若是不存在這個case文件夾,就自動建立一個
    if not os.path.exists(case_path):os.mkdir(case_path)
    # 定義discover方法的參數
    discover = unittest.defaultTestLoader.discover(case_path,
                                                  pattern=rule,
                                                  top_level_dir=None)
    return discover

# 執行報告
def run_case(discover):
    report_path =  os.path.join(path,'report')
    now = time.strftime("%Y-%m-%d-%H-%M-%S")  # 最新的報告
    report_abspath = os.path.join(report_path, now+"result.html")  # 報告的位置
    rp=open(report_abspath,"wb")
    runner=HTMLTestRunner_cn.HTMLTestRunner(rp,
                                        title=u"測試報告",
                                        description=u"用例的執行狀況")
    runner.run(discover)
    return report_abspath


def sen_mail(file_path):
    smtpserver = 'smtp.163.com'
    # 發送郵箱用戶名密碼
    user = 'xxxxxx@163.com'
    password = 'xxxxxx'
    # 發送郵箱
    sender = 'xxxxxx@163.com'
    # 接收郵箱
    receiver ='821006052@qq.com'
    #導入報告
    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'自動化測試報告'
    msg['from']=sender # 發送郵件
    msg['to']=receiver # 接手郵件
    msg.attach(body)
    att = MIMEText(mail_body, "base64", "utf-8")   # 生成附件
    att["Content-Type"] = "application/octet-stream"
    att["Content-Disposition"] = 'attachment; filename="report.html"' # 生成附件名稱
    msg.attach(att)
    smtp = smtplib.SMTP()
    smtp.connect(smtpserver)   # 鏈接服務器
    smtp.login(user,password)  # 登陸服務器
    # 發送郵件  split(',')分隔符
    smtp.sendmail(sender, receiver.split(','), msg.as_string())     # 關閉
    print ("郵件發送")

def main():
     discover = add_case() # 調用執行 執行用例
     file_path = run_case(discover) # 用例生成報告
     # sen_mail(file_path) # 發送報告

if __name__=="__main__":
    # add_case()
    t1 = threading.Thread(target=start)
    t1.start()
    time.sleep(20)
    t2 = threading.Thread(target=main)
    t2.start()

 

總體的PO模型設計都已經理完了,相信你們確定都會有一種體驗,怎麼感受原始的方法比較簡單,代碼還少,還簡單,可是若是測試用例較多呢?那麼是否是以爲這樣方法就很簡單,很已讀。

這裏咱們在回覆前面留下的那個問題? 自動化框架有什麼用?

若是自動化框架創建起來了,那麼組裏一些代碼基礎比較弱的同窗,均可以本身進行按照一個模板進行編寫測試用例。若是頁面元素或者UI發生了變化,咱們只須要找到對應的page和元素信息進行修改,這樣就能夠繼續保持之前的用例了。

那麼當中PO模型也佔了很大的用途,很清楚的使咱們代碼更加簡潔,已讀。也方便維護。

 

 

經過上面的內容,相信你們對PO模型有了簡單的瞭解,也相信你們都有不一樣的分層,這裏能夠留言一塊兒進行討論,學習更多方便簡單的方法

相關文章
相關標籤/搜索