IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> webui自动化测试框架(2)——对基本操作进行封装common -> 正文阅读

[开发测试]webui自动化测试框架(2)——对基本操作进行封装common

接上篇:webui自动化测试框架(1)——框架介绍
在这里插入图片描述

封装driver.py:
driver的初始化,查找元素,点击元素,输入内容,切换iframe,切换Windows等
1.类,构造函数init里面适配浏览器,浏览器的窗口最大化,设置隐式等待,默认20秒。
2.定位元素进行封装find_element方法
参数ele_info 数据类型是字典的类型{‘type’:‘xpath’,‘value’:‘xxx’},type表示定位类型,value表示元素定
位的值
返回值是目标元素
3.get_by方法 主要是获取最终的定位类型和元素定位的值,即locator=(type,value)
4.click方法 采用之前封装的显示等待的条件
5.get 打开浏览器链接
6.quit 退出浏览器
7.page_source:获取页面源码
8.page_contains:测试用例层做断言用的,这里面采用显示等待的方式,lambda匿名函数如果包含返回True,否则返回False。

封装driver.py

浏览器

webUI自动化大多数公司用的是Chrome浏览器,但也不排除其他浏览器的使用,还有一种情况是在要求测试兼容性的时候,会用到不同的浏览器,因此需要对不同的浏览器进行适配(前提:不同浏览器都安装了对应的webdriver)
这里封装了Chrome、Firefox、IE、edge浏览器,可以根据实际情况自行往里添加相关浏览器
代码如下:

class InitDriver:
    def __init__(self,browser:str):
        self.logger = GetLogger().get_logger()
        # 适配不同浏览器
        if browser.lower() == 'chrome':
            self.driver = webdriver.Chrome()
        elif browser.lower() == 'firefox':
            self.driver = webdriver.Firefox()
        elif browser.lower() == 'ie':
            self.driver = webdriver.Ie()
        elif browser.lower() == 'edge':
            self.driver = webdriver.Edge()
        else:
            self.logger.error('不支持的浏览器类型:{}'.format(browser))
            raise Exception('不支持的浏览器类型:{}'.format(browser))
        # 浏览器最大化
        self.driver.maximize_window()
        # 隐式等待-一般写10即可
        self.driver.implicitly_wait(20)

元素信息

传入元素可作为目标元素,供后面的鼠标操作和定位时调用

def find_element(self,ele_info):
        try:
            locator = self.get_by(ele_info)  # 元组
            el = self.driver.find_element(*locator)
            self.logger.info(f'查找{ele_info}元素成功')
            return el
        except Exception as e:
            self.logger.error(f'查找{ele_info}元素失败,报错信息为{e}')
            raise Exception(f'查找{ele_info}元素失败,报错信息为{e}')

在这里插入图片描述

网页地址

根据需求不同,每次登陆的网址也不同,这里对打开的目标网址也写了一个方法,后面可以直接调用

def get(self,url):
        # 打开目标的网址
        self.driver.get(url)
        self.logger.info(f'登录{url}网站')

点击操作

自动化测试过程中无时无刻不涉及鼠标和键盘操作,除了元素定位以外,其他都是由键盘和鼠标操作来完成的。比如一个简单的搜索动作,首先通过键盘向搜索框键入内容(send_keys),然后通过鼠标点击搜索按钮(click)完成搜索
在selenium中,所有的键盘鼠标动作都来自于一个类ActionChains,先来导入它

from selenium.webdriver.common.action_chains import ActionChains

定位到元素,然后进行点击

def click(self,ele_info):
        try:
            wait=WebDriverWait(self.driver,20)
            locator = self.get_by(ele_info)
            wait.until(element_click_is_success(locator))
            self.logger.info(f'元素{ele_info}点击成功')
        except Exception as e:
            self.logger.error(f'元素{ele_info}点击失败,报错信息为{e}')
            raise Exception(f'元素{ele_info}点击失败,报错信息为{e}')

输入操作

def send_keys(self,ele_info,text):
        try:
            element = self.find_element(ele_info)
            # 清空
            element.clear()
            # 输入
            element.send_keys(text)
            # 打日志信息
            self.logger.info(f'元素{ele_info}输入文本内容{text}成功')
        except Exception as e:
            self.logger.error(f'{ele_info}输入失败,报错信息为{e}')
            raise Exception(f'{ele_info}输入失败,报错信息为{e}')

页面源码(用于断言)

def page_source(self):
        try:
            self.logger.info('获取页面源码')
            return self.driver.page_source
        except Exception as e:
            self.logger.error(f'获取页面源码失败,报错信息为{e}')
            raise Exception(f'获取页面源码失败,报错信息为{e}')

断言:提示信息是否在页面源码中

def page_contains(self,text):
        try:
            wait = WebDriverWait(self.driver,20)
            # d表示的就是self.driver对象
            flag =wait.until(lambda d: text in d.page_source)
            self.logger.info(f'页面源码中包含{text}文本')
        except Exception as e:
            flag = False
            self.logger.warn(f'页面源码中不包含{text},报错信息不包含{e}')
        return flag

退出浏览器

每个测试场景类测试完成后都需要推出浏览器,也就意味着每个case都要写一次退出,所以在这里也把推出写成了一个方法,后面通过调用就可以了

def quit(self):
        try:
            self.driver.quit()
            self.logger.info('driver退出成功')
        except Exception as e:
            self.logger.error(f'driver退出失败,报错信息为{e}')

定位方式

这里只封装了几种基本元素定位方式:
id、name、classname、tagname、css、xpath、linktext、plinktext
复数定位可以自行加上

def get_by(self,ele_info):
        '''
        主要是获取定位策略locator的值
         ele_info数据类型是自己设计的,字典
               ele_info = {'type':name/xpath/id/css/classname/tagname/linktext/plinktext,'value':值}
               type = ele_info.get('type')  # 定位策略
               value = ele_info.get('value')  # 值
               driver.find_element(type,value).send_keys('123456789')
        :return:  具体的locator
        '''

        type = ele_info.get('type')  # 定位策略
        value = ele_info.get('value')  # 值
        if type == 'id':
            locator = (By.ID, value)
        elif type == 'name':
            locator = (By.NAME, value)
        elif type == 'classname':
            locator = (By.CLASS_NAME, value)
        elif type == 'tagname':
            locator = (By.TAG_NAME, value)
        elif type == 'css':
            locator = (By.CSS_SELECTOR, value)

        elif type == 'xpath':
            locator = (By.XPATH, value)

        elif type == 'linktext':
            locator = (By.LINK_TEXT, value)

        elif type == 'plinktext':
            locator = (By.PARTIAL_LINK_TEXT, value)
        else:
            # raise 抛出异常 代码不会继续往下运行
            self.logger.error(('不支持的浏览器类型:{}'.format(type)))
            raise Exception('不支持的浏览器类型:{}'.format(type))
        self.logger.info(f'元素的定位策略是{locator}')
        return locator

鼠标悬停

什么地方会用到鼠标悬停的动作呢?
比如选择省市区这类的下拉框或者选择框的的时候就会涉及到鼠标悬停的动作了。

def move_to_element(self,ele_info):
        '''
        鼠标悬浮
        :return:
        '''
        try:
            # 先定位到目标元素
            el=self.find_element(ele_info)
            # 鼠标悬浮在这个元素上面
            action=ActionChains(self.driver)
            action.move_to_element(el).perform()
            self.logger.info(f'鼠标悬浮元素{ele_info}成功')
        except Exception as e:
            self.logger.error(f'鼠标悬浮元素{ele_info}失败,报错信息为{e}')
            # 抛出异常
            raise Exception(f'鼠标悬浮元素{ele_info}失败,报错信息为{e}')

截图

这里主要是截取测试用例失败时的截图,也就是测试用例在哪里失败的就会在哪里截图

def get_screenshot_as_png(self):
        try:
            png = self.driver.get_screenshot_as_png()
            self.logger.info('截图成功')
            return png
        except Exception as e:
            self.logger.error(f'截图失败,报错信息为{e}')
            # 抛出异常
            raise Exception(f'截图失败,报错信息为{e}')
    # 截图并保存成文件的形式
    def get_screenshot_as_file(self,filepath):
        try:
            self.driver.get_screenshot_as_file(filepath)
            self.logger.info('截图并保存成功')
        except Exception as e:
            self.logger.error(f'截图并保存失败,报错信息为{e}')
            # 抛出异常
            raise Exception(f'截图失败,报错信息为{e}')

切换窗口

def switch_window(self):
        # 点击目标商品需要等会才能显示多窗口时的解决办法: 1.死等2.显示等待
        # time.sleep(2)
        try:
            handles = self.driver.window_handles
            wait = WebDriverWait(self.driver,10)
            wait.until(window_be_switch_success(handles[-1]))
            self.logger.info('切换窗口成功')
        except Exception as e:
            self.logger.error(f'切换窗口失败,报错信息为{e}')
            # 抛出异常
            raise Exception(f'切换窗口失败,报错信息为{e}')

获取文本内容

获取文本内容主要适用于断言使用,判断获取的文本内容是否在页面源码中存在

def get_text(self,ele_info):
        el = self.find_element(ele_info)
        try:
            text = el.text
            self.logger.info(f'获取元素文本内容成功,内容是{text},类型是{type(text)}')
            return text
        except Exception as e:
            self.logger.error(f'获取元素文本内容失败,报错信息为{e}')
            # 抛出异常
            raise Exception(f'获取元素文本内容失败,报错信息为{e}')

显示等待封装无法点击not clickable

class element_click_is_success:
    def __init__(self,locator):
        self.locator = locator
    # until - 函数-只有一个参数-driver
    def __call__(self,driver):  # 定义函数的过程:定义参数,返回值,运行代码
        # 函数就是对象=类名()等价于函数的名字
        try:
            # 不定长参数  args元组 *元组   语法升级
            driver.find_element(*self.locator).click()
            return True
        except Exception:
            return False

# 切换窗口,自定义一个显示等待的方法 切换成功
class window_be_switch_success:
    def __init__(self,handle):
        self.handle = handle
    def __call__(self,driver):
        try:
            driver.switch_to.window(self.handle)
            return True
        except Exception:
            return False

封装file_load.py

和接口自动化的那个文件一样,可以直接copy过来

def read_yaml(filename):
	'''
	读取yaml文件
	pip install pyyaml
	:return:
	路径:绝对路径
	相对路径:相对的是哪个文件??
	相对的是你运行的那个文件
	'../data/mtxshop.yml' 相对file_load.py
	'./data/mtxshop.yml' 相对run.py
	动态生成绝对路径
	解决方案:
	动态生成绝对路径
	1.获取当前项目的绝对路径
	2.跟读取的数据进行拼接
	'''
	with open(DIR_NAME+filename,'r',encoding='utf-8') as f:
		# 读取yml文件
		content =yaml.load(f,Loader=yaml.FullLoader)
		return content


def read_excel(filename,sheet_name):
	'''
	pip install pandas
	pip install openpyxl
	pip install xlrd
	:param filename: 你要读取的文件的名字
	:return:
	'''
	pd=pandas.read_excel(DIR_NAME+filename,sheet_name=sheet_name,
					  # 如果碰到空的单元格,默认是返回nan,python没有办法解析
					  # 所以让keep_default_na=False就会返回空字符串,
					  keep_default_na=False,
					  engine='openpyxl')
	# 总行数
	lines_count = pd.shape[0]  # 获取总的行数(不包含头部)
	# 总列数
	col_count = pd.columns.size # 获取总列数
	# 获取单元格的方法的索引值是从0开始的
	data=[]
	# 父循环控制行数
	for row in range(lines_count):  # 遍历行
		line = []  # 存放同一行中不同列的数据
		# 子循环控制列数
		for col in range(col_count): # 遍历列
			text=pd.iloc[row,col]  # 行和列组合交叉定位到一个单元格,可以拿到其内容
			# 判断  如果列数==1的时候  请求参数  text正常读取是字符串 text转换成字典
			if col == 1:
				text=json.loads(text)  # 将json格式的字符串转换成字典
			line.append(text)
		data.append(line)
	return data




if __name__ == '__main__':
	# print(read_yaml('/data/mtxshop.yml')['buynow'])
	# data = read_excel('/data/buyer.xlsx','立即购买')
	# print(data)
	# print(read_yaml('/config/db.yml')['test'])
	print(read_yaml('/pagefiles/buyer.yml'))

封装logger.py

和接口自动化的那个文件一样,可以直接copy过来

import logging.handlers
from setting import DIR_NAME


class GetLogger:
    '''
    当已经创建了logger对象的时候,那么之后就不在创建了,也就是只创建一次对象
    '''
    # 把logger对象的初始值设置为None
    logger = None

    # 创建logger,并且返回这个logger
    @classmethod
    def get_logger(cls):
        if cls.logger is None:
            ########创建日志器,控制他的创建次数
            cls.logger = logging.getLogger('apiautotest')  # 不是None
            # 设置总的级别,debug/info/warning/error
            # 只有比debug级别高的日志才会被显示出来
            cls.logger.setLevel(logging.DEBUG)
            # 2获取格式器
            # 2.1 要给格式器设置要输出的样式
            fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d] - %(message)s"
            # 2.2创建格式器,并且给他设置样式
            fm = logging.Formatter(fmt)
            # 3.创建处理器 按照时间进行切割文件
            tf = logging.handlers.TimedRotatingFileHandler(filename=DIR_NAME +'/logs/requests.log',  # 原日志文件
                                                           when='H',  # 间隔多长时间把日志存放到新的文件中
                                                           interval=1,
                                                           backupCount=3,  # 除了原日志文件,还有3个备份
                                                           encoding='utf-8'
                                                           )
            logging.basicConfig(level=logging.DEBUG,format=fmt) #这是在控制台上打印日志信息

            # 在处理器中添加格式器
            tf.setFormatter(fm)
            # 在日志器中添加处理器
            cls.logger.addHandler(tf)

            # return cls.logger
        return cls.logger


if __name__ == '__main__':
    logger = GetLogger().get_logger()
    print(id(logger))
    logger1 = GetLogger().get_logger()
    print(id(logger1))
    logger.debug('调试')  # 相当print小括号中的信息
    logger.info('信息')
    logger.warning('警告')
    name = '123'
    logger.error('这个变量是{}'.format(name))
    logger.critical('致命的')

待补充,更新中。。。

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-08-24 15:51:40  更:2021-08-24 15:51:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/14 22:41:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码