使用selenium + pytest + allure做WBE UI自动化
目录结构
依然使用了常见的po 模式
- 目录结构
- config
- config.ini 修改目标路由与相关配置
- elements
- 抽象页面空间元素
- method
- 抽象页面方法
- TestCase
- 测试用例
- utils
- Assert 自定义断言
- chromedriver 浏览器驱动 需匹配版本 非linux 环境无视
- Driver 初始化driver
- graphical 图片相对定位
- log 日志
- seleniumBase api封装
- seleniumOpt opt定义
- config
初始化Driver
根据判断运行环境 选择不同的chrome driver 或者使用
ChromeDriverManager
自动下载
class Driver:
@classmethod
def driver(cls):
try:
# select local or docker
# if platform == "Darwin":
# url = Config().get_conf("dockerHub", "url")
# driver = webdriver.Remote(url, desired_capabilities=capabilities(),
# options=options())
# # else:
if platform.system() == "Linux":
executable_path = os.path.join(os.path.dirname(__file__), "chromedriver")
driver = webdriver.Chrome(executable_path=executable_path, options=options())
else:
executable_path = ChromeDriverManager().install()
driver = webdriver.Chrome(executable_path=executable_path, options=options())
driver.implicitly_wait(20)
log.info(f"driver:{driver.name}")
return driver
except BaseException as e:
log.error(e)
raise e
自定义
driver
的options
配置
def options():
"""
浏览器设置
:return:
"""
_options = ChromeOptions()
# # 设置chrome为手机界面
# mobileEmulation = Config().get_conf("seleniumOpt", "mobileEmulation")
# if mobileEmulation == 'true':
# mobile_emulation = {"deviceName": "Galaxy S5"}
# _options.add_experimental_option("mobileEmulation", mobile_emulation)
if platform.system() == 'Darwin':
pass
else:
_options.add_argument('--headless')
_options.add_argument('--no-sandbox')
_options.add_argument('--disable-gpu')
_options.add_argument('--disable-dev-shm-usage')
return _options
Base类
封装常用API 把
driver
实例化传入
查找元素尽量使用显示等待expected_conditions
使用了Faker
可随意生成测试数据
查找元素失败 使用allure
上传截图
class SeleniumBaseConfig:
faker = Faker(locale="zh_CN")
Assert = Assert
log = get_log()
def __init__(self, driver: webdriver):
"""
:param driver: 驱动
"""
self.driver = driver
def find_element(self, locator: tuple, timeout=5):
"""
find_element
:param locator: (xpath,xxx)(id,xxx)
:param timeout: timeout
:return:
"""
try:
element = WebDriverWait(self.driver, timeout).until(EC.presence_of_element_located(locator))
self.log.info(f"[{self.find_element.__name__}] locator: {locator} element: {str(element)}")
return element
except WebDriverException as e:
self.log.error(e)
allure.attach(self.get_png(), "异常截图", allure.attachment_type.PNG)
allure.attach("未找到: {}, 详细信息如下: {}".format(locator, e))
raise e
自定Assert
很常规 没什么可说的
class Assert:
@staticmethod
def assert_unequal(exp, res):
try:
log.info("ASSERT UNEQUAL: EXPECT IS [{}] RESULT IS [{}]".format(exp, res))
assert exp != res
return True
except AssertionError as e:
log.error("ASSERT UNEQUAL ERROR: EXPECT IS [{}] RESULT IS [{}]".format(exp, res))
raise e
关于页面元素
根据op 依旧对页面抽象成类 并继承
SeleniumBaseConfig
元素类1一对1配套
class RegisterMethod(SeleniumBaseConfig):
def __init__(self, driver):
super().__init__(driver)
def register(self, mobile: str):
"""
注册
:param mobile
:return:
"""
self.send_keys(RegisterLogin.INPUT_NUMBER, mobile)
self.click(RegisterLogin.NEXT_STEP_BUTTON)
time.sleep(1)
对应元素类
class Register:
# ================== 公共 ================
# 下一步
NEXT_STEP_BUTTON = ("xpath", "//button")
# 返回
RETURN = ('xpath', '//p[@class="return-prev-step"]')
# input 错误信息
INPUT_ERROR_INFO = ("xpath", '//p[@class="default-input-error"]')
# ================== home界面 ================
CREATE_BUTTON = ("xpath", "//div[text()='创建']") # 创建button
JOIN_BUTTON = ("xpath", "//div[text()='加入']") # 创建button
INPUT_TEAM_NAME = ("xpath", '//input[@placeholder="请输入团队名称"]') # 输入团队名称
INPUT_YOUR_NAME = ("xpath", '//input[@placeholder="请输入你的姓名"]') # 输入个人名称
测试用例
@pytest.mark.P3
@allure.title("创建新团队:姓名输入汉字、英文、数字字符")
@pytest.mark.flaky(reruns=1, reruns_delay=2)
def test_create_team_username(self):
"""
姓名输入汉字、英文、数字字符
1.register
2.create team
3.create_team_username
"""
pics = []
self.driver.register(self.mobile)
exp = "true"
res = self.driver.check_button_disabled()
self.driver.allure_report(self.test_create_team_username, pics, exp, res)
self.driver.Assert.assert_equal(exp, res)
Config 配置
一般配置
host
等数据 使用ConfigParser
读取写入config.ini
[loginParam]
username = username
password = 123456
[domain]
cm = xx
class Config:
def get_conf(self, title, value):
"""
read .ini
:param title:
:param value:
:return:
"""
log.info("{} : {}:{}".format(self.get_conf.__name__, title, value))
return self.config.get(title, value)
def set_conf(self, title, value, text):
"""
change .ini
:param title:
:param value:
:param text:
:return:
"""
log.info("{} : {}:{}:{}".format(self.set_conf.__name__, title, value, text))
self.config.set(title, value, text)
with open(self.config_path, 'w ') as f:
return self.config.write(f)
main 启动
使用
sys.argv
获取命令行自定义参数
if len(sys.argv) > 3:
runCase = sys.argv[1] # P1 P2 P3 ALL 指定运行的用例等级
if runCase != "ALL":
case_path = f"-m={runCase}"
xml = sys.argv[2] # 报告路径
if xml:
xml_report_path = xml
BUILD_NUMBER = sys.argv[3]
args = ["-s", "-v", "-n=auto", case_path, '--alluredir', xml_report_path, '--clean-alluredir']
pytest.main(args=args)
图片相对定位 获得坐标
场景
canvas 页面 无元素可定位
使用
先截取想要点击的位置图片 保存到本地
find_me
传入driver
对象
通过center_x
与center_y
属性方法 获得相对坐标
class GraphicalLocator():
def __init__(self, img_path):
self.locator = img_path
# x, y position in pixels counting from left, top corner
self.x = None
self.y = None
self.img = cv2.imread(img_path)
self.height = self.img.shape[0]
self.width = self.img.shape[1]
self.threshold = None
@property
def center_x(self):
return self.x int(self.width / 2) if self.x and self.width else None
@property
def center_y(self): return self.y int(self.height / 2) if self.y and self.height else None
def find_me(self, drv): # Clear last found coordinates
self.x = self.y = None
# Get current screenshot of a web page
scr = drv.get_screenshot_as_png()
# Convert img to BytesIO
scr = Image.open(BytesIO(scr))
# Convert to format accepted by OpenCV
scr = numpy.asarray(scr, dtype=numpy.float32).astype(numpy.uint8)
# Convert image from BGR to RGB format
scr = cv2.cvtColor(scr, cv2.COLOR_BGR2RGB)
# Image matching works only on gray images
# (color conversion from RGB/BGR to GRAY scale)
img_match = cv2.minMaxLoc(
cv2.matchTemplate(cv2.cvtColor(scr, cv2.COLOR_RGB2GRAY),
cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY),
cv2.TM_CCOEFF_NORMED))
# Calculate position of found element
self.x = img_match[3][0]
self.y = img_match[3][1]
# From full screenshot crop part that matches template image
scr_crop = scr[self.y:(self.y self.height),
self.x:(self.x self.width)]
# Calculate colors histogram of both template# and matching images and compare them
scr_hist = cv2.calcHist([scr_crop], [0, 1, 2], None,
[8, 8, 8], [0, 256, 0, 256, 0, 256])
img_hist = cv2.calcHist([self.img], [0, 1, 2], None,
[8, 8, 8], [0, 256, 0, 256, 0, 256])
comp_hist = cv2.compareHist(img_hist, scr_hist,
cv2.HISTCMP_CORREL)
# Save treshold matches of: graphical image and image histogram
self.threshold = {'shape': round(img_match[1], 2), 'histogram': round(comp_hist, 2)}
# Return image with blue rectangle around match
return cv2.rectangle(scr, (self.x, self.y),
(self.x self.width, self.y self.height),
(0, 0, 255), 2)
pytest
pytest 有很多好用的功能、比如失败重跑、多进程并行用例、
fixture
测试
用例参数化等等
详见 gitHUB-SeleniumUIAuto 中的 readme
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgcfegj
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01