当前位置:网站首页>Selenium+Pytest自动化测试框架实战
Selenium+Pytest自动化测试框架实战
2022-07-06 08:57:00 【自动化测试七叔】
前言
今天呢笔者想和大家来聊聊selenium自动化+ pytest测试框架,在这篇文章里你需要知道一定的python基础——至少明白类与对象,封装继承;一定的selenium基础。这篇文章不会selenium,不会的可以自己去看selenium中文翻译网哟。
一、测试框架简介
测试框架有什么优点呢:
- 代码复用率高,如果不使用框架的话,代码会很冗余
- 可以组装日志、报告、邮件等一些高级功能
- 提高元素等数据的可维护性,元素发生变化时,只需要更新一下配置文件
- 使用更灵活的PageObject设计模式
- 测试框架的整体目录
- 目录/文件说明是否为python包common这个包中存放的是常见的通用的类,如读取配置文件是config配置文件目录是logs日志目录page对selenium的方放进行深度的封装是page_element页面元素存放目录page_object页面对象POM设计模式,TestCase所有的测试用例集是utils工具类是script脚本文件conftest.pypytest胶水文件pytest.inipytest配置文件,这样一个简单的框架结构就清晰了。
知道了以上这些我们就开始吧!
我们在项目中先按照上面的框架指引,建好每一项目录。
注意:python包为是的,都需要添加一个__init__.py文件以标识此目录为一个python包。
二、管理时间
首先呢,因为我们很多的模块会用到时间戳,或者日期等等字符串,所以我们先单独把时间封装成一个模块。
然后让其他模块来调用即可。在utils目录新建times.py模块
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import time
import datetime
from functools import wraps
def timestamp():
"""时间戳"""
return time.time()
def dt_strftime(fmt="%Y%m"):
"""
datetime格式化时间
:param fmt "%Y%m%d %H%M%S
"""
return datetime.datetime.now().strftime(fmt)
def sleep(seconds=1.0):
"""
睡眠时间
"""
time.sleep(seconds)
def running_time(func):
"""函数运行时间"""
@wraps(func)
def wrapper(*args, **kwargs):
start = timestamp()
res = func(*args, **kwargs)
print("校验元素done!用时%.3f秒!" % (timestamp() - start))
return res
return wrapper
if __name__ == '__main__':
print(dt_strftime("%Y%m%d%H%M%S"))
三、添加配置文件
配置文件是项目中必不可少的部分!
将固定不变的信息集中在固定的文件中
3.1conf.py
项目中都应该有一个文件对整体的目录进行管理,我也在这个python项目中设置了此文件。
在项目config目录创建conf.py文件,所有的目录配置信息写在这个文件里面。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import os
from selenium.webdriver.common.by import By
from utils.times import dt_strftime
class ConfigManager(object):
# 项目目录
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 页面元素目录
ELEMENT_PATH = os.path.join(BASE_DIR, 'page_element')
# 报告文件
REPORT_FILE = os.path.join(BASE_DIR, 'report.html')
# 元素定位的类型
LOCATE_MODE = {
'css': By.CSS_SELECTOR,
'xpath': By.XPATH,
'name': By.NAME,
'id': By.ID,
'class': By.CLASS_NAME
}
# 邮件信息
EMAIL_INFO = {
'username': '[email protected]', # 切换成你自己的地址
'password': 'QQ邮箱授权码',
'smtp_host': 'smtp.qq.com',
'smtp_port': 123
}
# 收件人
ADDRESSEE = [
'[email protected]',
]
@property
def log_file(self):
"""日志目录"""
log_dir = os.path.join(self.BASE_DIR, 'logs')
if not os.path.exists(log_dir):
os.makedirs(log_dir)
return os.path.join(log_dir, '{}.log'.format(dt_strftime()))
@property
def ini_file(self):
"""配置文件"""
ini_file = os.path.join(self.BASE_DIR, 'config', 'config.ini')
if not os.path.exists(ini_file):
raise FileNotFoundError("配置文件%s不存在!" % ini_file)
return ini_file
cm = ConfigManager()
if __name__ == '__main__':
print(cm.BASE_DIR)
注意:QQ邮箱授权码怎么生成自己去百度
这个conf文件我模仿了Django的settings.py文件的设置风格,但是又有些许差异。
在这个文件中我们可以设置自己的各个目录,也可以查看自己当前的目录。
遵循了约定:不变的常量名全部大写,函数名小写。看起来整体美观。
3.2config.ini
在项目config目录新建一个config.ini文件,里面暂时先放入我们的需要测试的URL
[HOST]
HOST = https://www.baidu.com
四、读取配置文件
配置文件创建好了,接下来我们需要读取这个配置文件以及使用里面的信息。
我们在common目录中新建一个readconfig.py文件
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import configparser
from config.conf import cm
HOST = 'HOST'
class ReadConfig(object):
"""配置文件"""
def __init__(self):
self.config = configparser.RawConfigParser() # 当有%的符号时请使用Raw读取
self.config.read(cm.ini_file, encoding='utf-8')
def _get(self, section, option):
"""获取"""
return self.config.get(section, option)
def _set(self, section, option, value):
"""更新"""
self.config.set(section, option, value)
with open(cm.ini_file, 'w') as f:
self.config.write(f)
@property
def url(self):
return self._get(HOST, HOST)
ini = ReadConfig()
if __name__ == '__main__':
print(ini.url)
可以看到我们用python内置的configparser模块对config.ini文件进行了读取。
对于url值的提取,我使用了高阶语法@property属性值,写法更简单。
五、记录操作日志
日志,大家应该都很熟悉这个名词,就是记录代码中的动作。
在utils目录中新建logger.py文件。
这个文件就是我们用来在自动化测试过程中记录一些操作步骤的。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import logging
from config.conf import cm
class Log:
def __init__(self):
self.logger = logging.getLogger()
if not self.logger.handlers:
self.logger.setLevel(logging.DEBUG)
# 创建一个handle写入文件
fh = logging.FileHandler(cm.log_file, encoding='utf-8')
fh.setLevel(logging.INFO)
# 创建一个handle输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# 定义输出的格式
formatter = logging.Formatter(self.fmt)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# 添加到handle
self.logger.addHandler(fh)
self.logger.addHandler(ch)
@property
def fmt(self):
return '%(levelname)s\t%(asctime)s\t[%(filename)s:%(lineno)d]\t%(message)s'
log = Log().logger
if __name__ == '__main__':
log.info('hello world')
在终端中运行该文件,就看到命令行打印出了:
INFO 2022-06-15 16:00:05,467 [logger.py:38] hello world
然后在项目logs目录下生成了当月的日志文件。
六、简单理解POM模型
由于下面要讲元素相关的,所以首先理解一下POM模型
Page Object模式具有以下几个优点。
该观点来自 《Selenium自动化测试——基于Python语言》
- 抽象出对象可以最大程度地降低开发人员修改页面代码对测试的影响, 所以, 你仅需要对页
面对象进行调整, 而对测试没有影响; - 可以在多个测试用例中复用一部分测试代码;
- 测试代码变得更易读、 灵活、 可维护
Page Object模式图
- basepage ——selenium的基类,对selenium的方法进行封装
- pageelements——页面元素,把页面元素单独提取出来,放入一个文件中
- searchpage ——页面对象类,把selenium方法和页面元素进行整合
- testcase ——使用pytest对整合的searchpage进行测试用例编写
通过上图我们可以看出,通过POM模型思想,我们把:
- selenium方法
- 页面元素
- 页面对象
- 测试用例
以上四种代码主体进行了拆分,虽然在用例很少的情况下做会增加代码,但是当用例多的时候意义很大,代码量会在用例增加的时候显著减少。我们维护代码变得更加直观明显,代码可读性也变得比工厂模式强很多,代码复用率也极大的得到了提高。
这篇文章暂时到这里哟,后面会接着讲的哟。
边栏推荐
- LeetCode:124. Maximum path sum in binary tree
- Notes 01
- Warning in install. packages : package ‘RGtk2’ is not available for this version of R
- Export IEEE document format using latex
- UML diagram memory skills
- ROS compilation calls the third-party dynamic library (xxx.so)
- Simple use of promise in uniapp
- 广州推进儿童友好城市建设,将探索学校周边200米设安全区域
- 超高效!Swagger-Yapi的秘密
- Delay initialization and sealing classes
猜你喜欢
vb. Net changes with the window, scales the size of the control and maintains its relative position
[embedded] print log using JLINK RTT
Cesium draw points, lines, and faces
Improved deep embedded clustering with local structure preservation (Idec)
LeetCode:124. Maximum path sum in binary tree
TP-LINK enterprise router PPTP configuration
如何正确截取字符串(例:应用报错信息截取入库操作)
Export IEEE document format using latex
Deep anatomy of C language -- C language keywords
KDD 2022 paper collection (under continuous update)
随机推荐
Cesium draw points, lines, and faces
Navicat Premium 创建MySql 创建存储过程
LeetCode:26. 删除有序数组中的重复项
LeetCode:162. Looking for peak
What is an R-value reference and what is the difference between it and an l-value?
Problems encountered in connecting the database of the project and their solutions
UML圖記憶技巧
LeetCode:836. 矩形重叠
R language ggplot2 visualization, custom ggplot2 visualization image legend background color of legend
Implement window blocking on QWidget
Mongodb installation and basic operation
[OC]-<UI入门>--常用控件-UIButton
MongoDB 的安装和基本操作
What is the role of automated testing frameworks? Shanghai professional third-party software testing company Amway
Notes 01
Leetcode: Jianzhi offer 04 Search in two-dimensional array
Ijcai2022 collection of papers (continuously updated)
BN folding and its quantification
BN折叠及其量化
POI add write excel file