Python+Selenium+Unittest实现PO模式web自动化框架(2)
阅读原文时间:2023年07月12日阅读:2

basepage.py模块里面是封装的对元素的操作。例如:查找元素、点击元素、文本输入等等。

# --^_^-- coding:utf-8 --^_^--

@Remark:webdriver的封装

from Common import logger
import logging
import time
import datetime
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from Common.dir_config import screenshot_dir
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.select import Select
import win32gui
import win32con

class BasePage:
'''
包含了PageObjects当中,用到所有的selenium底层方法。
还可以包含通用的一些元素操作,如alert,iframe,windows…
还可以自己额外封装一些web相关的断言
实现日志记录、实现失败截图
'''
def __init__(self,driver):
self.driver = driver

# 实现网页截图操作  
def save\_web\_screenshot(self,img\_doc):  
    # 页面\_功能\_时间.png  
    now = time.strftime("%Y-%m-%d %H\_%M\_%S")  
    filepath = "{}-{}.png".format(now,img\_doc)  
    try:  
        self.driver.save\_screenshot(screenshot\_dir + "/" + filepath)  
        logging.info("网页截图成功!图片存储在:{}!".format(screenshot\_dir +"/" + filepath))  
    except:  
        logging.exception("网页截图失败!")  
        raise

# 等待元素可见  
def wait\_eleVisible(self,loc,img\_doc="",timeout=30,frequency=0.5):  
    logging.info("等待元素{}可见!".format(loc))  
    try:  
        # 起始等待的时间datetime  
        startTime = datetime.datetime.now()  
        # 等待元素  
        WebDriverWait(self.driver,timeout,frequency).until(EC.visibility\_of\_element\_located)  
        # 结束等待时间  
        endTime = datetime.datetime.now()  
        logging.info("等待元素成功!开始等待时间:{},结束等待时间:{},等待时长为:{}!".format(startTime, endTime, endTime - startTime))  
    except:  
        # 日志  
        logging.exception("等待元素可见失败!")  
        # 截图-哪一个页面哪一个操作导致的失败 + 当前时间  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 查找一个元素  
def get\_element(self, loc, img\_doc=""):  
    '''  
    :param loc: 元素定位,以元组的形式。(定位类型、定位时间)  
    :param img\_doc:截图的说明。例如:登录页面\_输入用户名  
    :return:webElement对象。  
    '''  
    logging.info("查找{}中的元素{}".format(img\_doc, loc))  
    try:  
        ele = self.driver.find\_element(\*loc)  
        logging.info("查找{}元素成功!".format(ele))  
        return ele  
    except:  
        # 日志  
        logging.exception("查找元素失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 等待元素出现,点击元素  
def click\_element(self, loc, img\_doc,timeout=30, frequency=0.5):  
    '''  
    :param loc:元素定位,以元组的形式。(定位类型、定位时间)  
    :param img\_doc:截图的说明。例如:登录页面\_输入用户名  
    :param timeout:等待元素的超时上限  
    :param frequency:等待元素可见时,轮询周期  
    :return:  
    '''  
    # 等待元素可见  
    self.wait\_eleVisible(loc, img\_doc, timeout, frequency)  
    # 查找元素  
    ele = self.get\_element(loc, img\_doc)  
    # 点击操作  
    logging.info("点击元素{}!".format(loc))  
    try:  
        ele.click()  
        logging.info("点击元素{}成功!".format(ele))  
    except:  
        # 日志  
        logging.exception("点击元素失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 文本输入  
def input\_text(self, loc, img\_doc, \*args):  
    '''  
    等待元素可见,找到元素,并在元素中输入文本信息  
    :param loc:元组形式的元素定位表达式  
    :param img\_doc:执行失败时,截图的文件命名  
    :param args:输入操作中,可以输入多个值,也可以组合按键  
    :return:  
    '''  
    # 等待元素出现  
    self.wait\_eleVisible(loc, img\_doc)  
    # 查找元素  
    ele = self.get\_element(loc, img\_doc)  
    # 清空输入框内容  
    self.clear\_data(loc,img\_doc)  
    # 文本输入  
    logging.info("给元素{}输入文本内容:{}".format(loc, \*args))  
    try:  
        ele.send\_keys(\*args)  
        logging.info("文本输入成功!")  
    except:  
        # 日志  
        logging.exception("文本输入失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 获取元素的属性值  
def get\_element\_attribute(self, loc, attr\_name, img\_doc):  
    '''  
    获取元素标签的内容  
    :param loc:元素定位,以元组的形式。(定位类型、定位时间)  
    :param attr\_name:属性名称  
    :param img\_doc:执行失败时,截图的文件命名  
    :return:  
    '''  
    # 等待元素出现  
    self.wait\_eleVisible(loc, img\_doc)  
    # 查找元素  
    ele = self.get\_element(loc, img\_doc)  
    # 获取属性  
    try:  
        attr\_value = ele.get\_attribute(attr\_name)  
        logging.info("获取元素{}的属性{}值为:{}!".format(loc, attr\_name, attr\_value))  
        return attr\_value  
    except:  
        # 日志  
        logging.exception("获取元素属性失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 获取元素的文本值  
def get\_element\_text(self, loc, img\_doc):  
    '''  
    :param loc:元素定位,以元组的形式。(定位类型、定位时间)  
    :param img\_doc:执行失败时,截图的文件命名  
    :return:  
    '''  
    # 等待元素出现  
    self.wait\_eleVisible(loc, img\_doc)  
    # 查找元素  
    ele = self.get\_element(loc,img\_doc)  
    # 获取文本值  
    try:  
        text = ele.text  
        logging.info("获取元素{}的文本值为:{}!".format(loc, text))  
        return text  
    except:  
        # 日志  
        logging.exception("获取元素文本值失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 鼠标悬浮操作  
def mouse\_suspension(self,loc, img\_doc):  
    # 实例化ActionChains  
    ac = ActionChains(self.driver)  
    # 等待元素出现  
    self.wait\_eleVisible(loc, img\_doc)  
    # 查找元素  
    ele = self.get\_element(loc)  
    # 鼠标悬浮  
    try:  
        ac.move\_to\_element(ele).perform()  
        time.sleep(1)  
        logging.info("鼠标悬浮成功!")  
    except:  
        # 日志  
        logging.exception("鼠标悬浮失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 进入到iframe中  
def get\_iframe(self,loc,img\_doc):  
    # 等待元素出现  
    self.wait\_eleVisible(loc, img\_doc)  
    # 查找元素  
    ele = self.get\_element(loc)  
    # 进入iframe  
    try:  
        self.driver.switch\_to.frame(ele)  
        logging.info("进入iframe中成功!")  
    except:  
        # 日志  
        logging.exception("进入到iframe中失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 通过文本选择下拉选择框  
def drop\_down\_select(self,loc,text,img\_doc):  
    # 等待元素出现  
    self.wait\_eleVisible(loc, img\_doc)  
    # 查找select元素  
    ele = self.get\_element(loc)  
    # 下拉选择  
    try:  
        Select(ele.select\_by\_visible\_text(text))  
        logging.info("选择select成功!")  
    except:  
        # 日志  
        logging.exception("下拉选择失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 选择非select的下拉选择框  
def drop\_down\_not\_select(self,loc1,loc2,img\_doc):  
    # 先定位到下拉菜单  
    # 等待元素出现  
    self.wait\_eleVisible(loc1, img\_doc)  
    # 查找下拉菜单元素  
    self.click\_element(loc1,"下拉菜单输入框")  
    logging.info("查找下拉菜单输入框成功!")  
    time.sleep(2)  
    # 在对下拉菜单的选项进行选择  
    try:  
        # 选择下拉菜单选项  
        # 等待元素出现  
        self.wait\_eleVisible(loc2, img\_doc)  
        self.click\_element(loc2,"选择下拉菜单选项")  
        logging.info("选择下拉菜单成功!")  
    except:  
        # 日志  
        logging.exception("下拉选择失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 清空输入框中的内容  
def clear\_data(self,loc,img\_doc):  
    # 等待元素出现  
    self.wait\_eleVisible(loc, img\_doc)  
    # 查找一个元素  
    ele = self.get\_element(loc)  
    # 清空输入框  
    try:  
        ele.clear()  
        logging.info("清空输入框成功!")  
    except:  
        # 日志  
        logging.exception("清空输入框失败!")  
        # 截图  
        self.save\_web\_screenshot(img\_doc)  
        raise

# 上传操作(前提 :windows上传窗口已经出现。sleep1-2秒等待弹出的出现。)  
def upload(filePath, browser\_type="chrome"):  
    if browser\_type == "chrome":  
        title = "打开"  
    else:  
        title = ""

    # 找元素  
    # 一级窗口"#32770","打开"  
    dialog = win32gui.FindWindow("#32770", title)  
    ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, "ComboBoxEx32", None)  # 二级  
    comboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, "ComboBox", None)  # 三级  
    # 编辑按钮  
    edit = win32gui.FindWindowEx(comboBox, 0, 'Edit', None)  # 四级  
    # 打开按钮  
    button = win32gui.FindWindowEx(dialog, 0, 'Button', "打开(&O)")  # 四级

    # 往编辑当中,输入文件路径.  
    win32gui.SendMessage(edit, win32con.WM\_SETTEXT, None, filePath)  # 发送文件路径  
    win32gui.SendMessage(dialog, win32con.WM\_COMMAND, 1, button)  # 点击打开按钮

dir_config.py模块里面封装的是项目当中需要用到的路径配置,该配置是相对项目来说的相对配置,这样项目无论放在哪里都能使用而不报错。

# --^_^-- coding:utf-8 --^_^--

@Remark:路径配置

import os

框架项目顶层目录

base_dir = os.path.split(os.path.split(os.path.abspath(__file__))[0])[0]

日志目录

logs_dir = os.path.join(base_dir, "Outputs/logs")

截屏目录

screenshot_dir = os.path.join(base_dir, "Outputs/screenshots")

测试数据目录

testdatas_dir = os.path.join(base_dir, "TestDatas")

测试用例目录

testcases_dir = os.path.join(base_dir, "TestCases")

测试报告目录

htmlreport_dir = os.path.join(base_dir, "Outputs/reports")

HTMLTestRunnerNew.py模块是用于生成HTML的测试报告模块。(具体的模块代码太长,不方便展示。有需要可私聊。)

logger.py模块是自定义的log日志模块。

# --^_^-- coding:utf-8 --^_^--

@Remark:日志模块

import logging
from logging.handlers import TimedRotatingFileHandler
import datetime
from Common import dir_config

fmt = "%(asctime)s %(levelname)s %(filename)s %(funcName)s [ line:%(lineno)d ] %(message)s"
datefmt = "%Y-%m-%d %H:%M:%S"

获取当前时间

now_time = datetime.datetime.now().strftime('%Y-%m-%d')

把当前时间转换成str

now_time_str = str(now_time)

handler_1 = logging.StreamHandler()
handler_2 = TimedRotatingFileHandler(dir_config.logs_dir + "/" + now_time_str + "_Web.log", when='D', interval=10,backupCount=0, encoding='utf-8')

设置rootlogger 的输出内容形式,输出渠道

logging.basicConfig(format=fmt, datefmt=datefmt, level=logging.INFO, handlers=[handler_1, handler_2])

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器