APP自動化針對PO模式進行二次封裝之basepage


  APP自動化跟WEB自動化所使用的框架基本一樣,都是采用的PO模式結合pytest框架編寫自動化測試腳本,為了提高代碼的復用性、穩定性和易維護性,我們針對PO模式進行了二次封裝,將日志,等待以及異常截圖加入到其中,app相比較web而言,沒有鼠標 、下拉框選擇、frame切換、窗口切換和上傳等操作,但它有屬於自己的滑屏、toast獲取、上下文切換、應用切換等操作。

import time
from datetime import datetime
import allure
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.webdriver import WebDriver
from Common.handle_logger import case_logger
from Common.constants import OUTPUTS_DIR


class BasePage:
    '''
    BasePage類,針對PageObjects類的二次封裝
    '''

    def __init__(self, driver: WebDriver):
        self.driver = driver

    def wait_element_to_be_visible(self, loc, img_doc, timeout=20, frequency=0.5):
        '''
        等待元素可見
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return:
        '''
        try:
            case_logger.info("開始等待頁面元素<{}>是否可見!".format(loc))
            start_time = time.time()
            WebDriverWait(self.driver, timeout, frequency).until(EC.visibility_of_element_located(loc))
        except Exception as e:
            case_logger.error("頁面元素<{}>等待可見失敗!".format(loc))
            self.save_screenshot(img_doc)
            raise e
        else:
            end_time = time.time()
            case_logger.info("頁面元素<{}>等待可見,等待時間:{}秒".format(loc, round(end_time - start_time, 2)))

    def wait_element_to_be_click(self, loc, img_doc, timeout=20, frequency=0.5):
        '''
        等待元素可點擊
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return:
        '''
        try:
            case_logger.info("開始等待頁面元素<{}>是否可點擊!".format(loc))
            start_time = time.time()
            WebDriverWait(self.driver, timeout, frequency).until(EC.element_to_be_clickable(loc))
        except Exception as e:
            case_logger.error("頁面元素<{}>等待可點擊失敗!".format(loc))
            self.save_screenshot(img_doc)
            raise e
        else:
            end_time = time.time()
            case_logger.info("頁面元素<{}>等待可點擊,等待時間:{}秒".format(loc, round(end_time - start_time, 2)))

    def wait_element_to_be_exist(self, loc, img_doc, timeout=20, frequency=0.5):
        '''
        等待元素存在
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return:
        '''
        try:
            case_logger.info("開始等待頁面元素<{}>是否存在!".format(loc))
            start_time = time.time()
            WebDriverWait(self.driver, timeout, frequency).until(EC.presence_of_element_located(loc))
        except Exception as e:
            case_logger.error("頁面元素<{}>等待存在失敗!".format(loc))
            self.save_screenshot(img_doc)
            raise e
        else:
            end_time = time.time()
            case_logger.info("頁面元素<{}>等待存在,等待時間:{}秒".format(loc, round(end_time - start_time, 2)))

    def save_screenshot(self, img_doc):
        '''
        頁面截屏保存截圖
        :param img_doc: 截圖說明
        :return:
        '''
        file_name = OUTPUTS_DIR + "\\{}_{}.png".format(datetime.strftime(datetime.now(), "%Y%m%d%H%M%S"), img_doc)
        self.driver.save_screenshot(file_name)
        with open(file_name, mode='rb') as f:
            file = f.read()
        allure.attach(file, img_doc, allure.attachment_type.PNG)
        case_logger.info("頁面截圖文件保存在:{}".format(file_name))

    def get_element(self, loc, img_doc):
        '''
        獲取頁面中的元素
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :return: WebElement對象
        '''
        case_logger.info("在{}中查找元素<{}>".format(img_doc, loc))
        try:
            ele = self.driver.find_element(*loc)
        except Exception as e:
            case_logger.error("在{}中查找元素<{}>失敗!".format(img_doc, loc))
            self.save_screenshot(img_doc)
            raise e
        else:
            return ele

    def get_elements(self, loc, img_doc):
        '''
        獲取頁面中的所有元素
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :return: WebElement對象
        '''
        case_logger.info("在{}中查找所有元素<{}>".format(img_doc, loc))
        try:
            ele = self.driver.find_elements(*loc)
        except Exception as e:
            case_logger.error("在{}中查找所有元素<{}>失敗!".format(img_doc, loc))
            self.save_screenshot(img_doc)
            raise e
        else:
            return ele

    def input_text(self, text, loc, img_doc, timeout=20, frequency=0.5):
        '''
        對輸入框輸入文本內容
        :param text: 輸入的文本內容
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return:
        '''
        try:
            case_logger.info("在{}中輸入元素<{}>的內容為{}".format(img_doc, loc, text))
            self.wait_element_to_be_visible(loc, img_doc, timeout, frequency)
            self.get_element(loc, img_doc).send_keys(text)
        except Exception as e:
            case_logger.error("在元素<{}>中輸入內容{}失敗!".format(loc, text))
            self.save_screenshot(img_doc)
            raise e

    def clear_text(self, loc, img_doc, timeout=20, frequency=0.5):
        '''
        清除文本框的內容
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return:
        '''
        try:
            case_logger.info("在{}中清除元素<{}>的文本內容".format(img_doc, loc))
            self.wait_element_to_be_click(loc, img_doc, timeout, frequency)
            self.get_element(loc, img_doc).clear()
        except Exception as e:
            case_logger.error("在{}中清除元素<{}>的文本內容失敗!".format(img_doc, loc))
            self.save_screenshot(img_doc)
            raise e

    def click_button(self, loc, img_doc, timeout=20, frequency=0.5):
        '''
        點擊按鈕
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return:
        '''
        try:
            case_logger.info("在{}中點擊元素<{}>".format(img_doc, loc))
            self.wait_element_to_be_click(loc, img_doc, timeout, frequency)
            self.get_element(loc, img_doc).click()
        except Exception as e:
            case_logger.error("在{}中點擊元素<{}>失敗!".format(img_doc, loc))
            self.save_screenshot(img_doc)
            raise e

    def get_element_text(self, loc, img_doc, timeout=20, frequency=0.5):
        '''
        獲取WebElement對象的文本值
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return: WebElement對象的文本值
        '''
        try:
            case_logger.info("在{}中獲取元素<{}>的文本值".format(img_doc, loc))
            self.wait_element_to_be_visible(loc, img_doc, timeout, frequency)
            text = self.get_element(loc, img_doc).text
        except Exception as e:
            case_logger.error("在{}中獲取元素<{}>的文本值失敗!".format(img_doc, loc))
            self.save_screenshot(img_doc)
            raise e
        else:
            case_logger.info("獲取到的元素文本值為:{}".format(text))
            return text

    def get_elements_text(self, loc, img_doc, timeout=20, frequency=0.5):
        '''
        獲取WebElement對象的所有文本值
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return: WebElement對象的文本值的列表
        '''
        try:
            case_logger.info("在{}中獲取元素<{}>的所有文本值".format(img_doc, loc))
            self.wait_element_to_be_visible(loc, img_doc, timeout, frequency)
            all_text = self.get_elements(loc, img_doc)
            text_list = []
            for one_text in all_text:
                text_list.append(one_text.text)
        except Exception as e:
            case_logger.error("在{}中獲取元素<{}>的所有文本值失敗!".format(img_doc, loc))
            self.save_screenshot(img_doc)
            raise e
        else:
            case_logger.info("獲取到的元素文本值列表為:{}".format(text_list))
            return text_list

    def get_element_attr(self, attr_name, loc, img_doc, timeout=20, frequency=0.5):
        '''
        獲取WebElement對象的屬性值
        :param attr_name: 屬性名稱
        :param loc: 元素定位的XPATH元組表達式
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return: WebElement對象的屬性值
        '''
        try:
            case_logger.info("在{}中獲取元素<{}>的屬性{}的值".format(img_doc, loc, attr_name))
            self.wait_element_to_be_exist(loc, img_doc, timeout, frequency)
            value = self.get_element(loc, img_doc).get_attribute(attr_name)
        except Exception as e:
            case_logger.error("在{}中獲取元素<{}>的屬性{}的值失敗!".format(img_doc, loc, attr_name))
            self.save_screenshot(img_doc)
            raise e
        else:
            case_logger.info("獲取到的元素屬性{}的值為{}".format(attr_name, value))
            return value

    def sliding_screen(self, direction, img_doc):
        '''
        滑屏操作
        :param direction: 滑屏方向:上-up;下-down;左-left;右-right
        :param img_doc: 截圖說明
        :return:
        '''
        size = self.driver.get_window_size()
        try:
            case_logger.info("開始向{}方向滑動".format(direction))
            if direction.lower() == 'up':
                self.driver.swipe(start_x=size['width'] * 0.5,
                                  start_y=size['height'] * 0.9,
                                  end_x=size['width'] * 0.5,
                                  end_y=size['height'] * 0.1,
                                  duration=200)
            elif direction.lower() == 'down':
                self.driver.swipe(start_x=size['width'] * 0.5,
                                  start_y=size['height'] * 0.1,
                                  end_x=size['width'] * 0.5,
                                  end_y=size['height'] * 0.9,
                                  duration=200)
            elif direction.lower() == 'left':
                self.driver.swipe(start_x=size['width'] * 0.9,
                                  start_y=size['height'] * 0.5,
                                  end_x=size['width'] * 0.1,
                                  end_y=size['height'] * 0.5,
                                  duration=200)
            elif direction.lower() == 'right':
                self.driver.swipe(start_x=size['width'] * 0.1,
                                  start_y=size['height'] * 0.5,
                                  end_x=size['width'] * 0.9,
                                  end_y=size['height'] * 0.5,
                                  duration=200)
            else:
                case_logger.error("方向選擇錯誤!")
        except Exception as e:
            case_logger.error("向{}方向滑動屏幕失敗!".format(direction))
            self.save_screenshot(img_doc)
            raise e

    def get_toast_msg(self, partial_text, img_doc):
        '''
        獲取toast文本信息
        :param partial_text: 不完整文本
        :param img_doc: 截圖說明
        :return: toast文本
        '''
        loc = (MobileBy.XPATH, '//*[contains(@text,"{}")]'.format(partial_text))
        try:
            WebDriverWait(self.driver, 10, 0.01).until(EC.presence_of_element_located(loc))
            msg = self.driver.find_element(*loc).text
            print("toast出現了!!!")
            return msg
        except Exception as e:
            print("好可惜,toast沒找到!!")
            case_logger.error("獲取toast文本失敗!")
            self.save_screenshot(img_doc)
            raise e

    def switch_to_webview(self, loc, img_doc, timeout=20, frequency=0.5):
        '''
        切換到webview頁面
        :param loc: webview頁面的元素
        :param img_doc: 截圖說明
        :param timeout: 等待的超時時間
        :param frequency: 輪詢頻率
        :return:
        '''
        try:
            case_logger.info("等待元素{}可見,並進行webview切換".format(loc))
            start_time = time.time()
            WebDriverWait(self.driver, timeout, frequency).until(EC.visibility_of_element_located(loc))
            cons = self.driver.contexts
            case_logger.info("開始切換到webview:{}".format(cons[-1]))
            self.driver.switch_to.context(cons[-1])
        except Exception as e:
            case_logger.error("切換webview失敗!")
            self.save_screenshot(img_doc)
            raise e
        else:
            end_time = time.time()
            case_logger.info("切換到webview:{}成功,等待時間:{}秒".format(cons[-1], round(end_time - start_time, 2)))

    def switch_to_native_app(self, img_doc):
        '''
        切換到app原生頁面
        :param img_doc: 截圖說明
        :return:
        '''
        try:
            case_logger.info("切換到app原生頁面")
            self.driver.switch_to.context('NATIVE_APP')
        except Exception as e:
            case_logger.error("切換到app原生頁面失敗!")
            self.save_screenshot(img_doc)
            raise e

    def application_switching(self, package_name, activity_name, img_doc):
        '''
        應用切換
        :param package_name: 包名
        :param activity_name: 歡迎頁面名
        :param img_doc: 截圖說明
        :return:
        '''
        try:
            case_logger.info("切換應用到{}".format(package_name))
            self.driver.start_activity(app_package=package_name, app_activity=activity_name)
        except Exception as e:
            case_logger.error("切換應用到{}失敗!".format(package_name))
            self.save_screenshot(img_doc)
            raise e

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM