应用场景:selenium+PO+YAML 架构的自动化测试结构
PO是Page Object ,即“页面对象模式”,是页面元素操作和业务流程相分离,代码结构比较清晰,提高了代码的复用性和降低代码维护成本。
下面按结构层进行讲述,以小米商城页面为例:
一、Base层
import yaml
# 保存页面操作中需要的公共方法
class BasePage():
# 初始化页面的操作
def __init__(self, driver):
self.driver = driver
eles = yaml.load(open('data.yaml', 'rb'), Loader=yaml.FullLoader)[self.__class__.__name__]
# Loader=yaml.FullLoader是加载器,更安全,以二进制读取,获取对应的class名
for ele in eles: # 根据字典动态赋值
self.__setattr__(ele, eles[ele])
# 点击操作
def click(self, *locator):
self.driver.find_element(*locator).click()
# 当元素存在就点击
def click_ele_exist(self, *locator):
self.driver.find_element(*locator)
btns = self.driver.find_elements(*locator)
# 如果出现用户协议弹出按钮
if btns:
btns[0].click()
# 输入元素定位
def input_text(self, text, *locator):
self.driver.find_element(*locator).send_keys(text)
# 根据css定位的元素
def by_js(self, css):
self.driver.execute_script(f"document.querySelector('{css}')")
# 切换目标窗口
def switch_window(self, target_title):
# 切换到产品详情页窗口
for handle in self.driver.window_handles:
self.driver.switch_to.window(handle)
# 判断切换到窗口句柄——-判断当前窗口的标题是否是:<header>中的<title>
if target_title == self.driver.title:
print("切换窗口句柄到产品详情页")
return True
# 获取目标元素文本
def get_text(self, *locator):
return self.driver.find_element(*locator).text
def get_url(self, url):
self.driver.get(url)
# 后退
def back(self):
self.driver.back()
# 前进
def forword(self):
self.driver.forword()
# 退出
def quit(self):
self.driver.quit()
二、Common层
# commons.py文件
# 获取项目路径、项目的各环境的url,处理数据文件的方法,框架执行相关日志功能的实现方法
import os, configparser
# os: 获取操作系统级别的目录/文件夹的操作和文件的操作(读取,写入)
# configparser: 在python中的主要功能是读取配置文件config.ini
# 获取config.ini路径
def congfig_path():
# return os.path.split(os.path.realpath(__file__))[0].split('C')[0]
# 获取当前文件的路径
curPath = os.path.dirname(os.path.realpath(__file__))
# 返回config.ini路径
return os.path.join(curPath, "config.ini")
# 返回config.ini中的testUrl
def config_url(key, value):
# 创建配置文件管理对象
config = configparser.ConfigParser()
# 读取config.ini文件
config.read(congfig_path(), encoding="utf-8")
return config.get(key, value)
if __name__ == '__main__':
print("项目路径是:" + congfig_path())
print("项目的url是: " + config_url('testUrl', 'url'))
# config.ini 文件
[testUrl]
url=https://www.mi.com/index.html
# 生产环境的url地址
[productUrl]
url=https://www.mi.com/index.html
三、Data层
# 首页
IndexPage:
# 前置默认空格是2个,key与值之间有1个空格
login_btn: ['css selector','#J_siteUserInfo>a:nth-child(1)']
user_proxy: ['css selector','.btn.btn-primary']
search_input: ['id','search']
# 登录页面
LoginPage:
user_input: ['xpath','//input[@name="account"]']
psw_input: ['xpath','//input[@name="password"]']
login_btn: ['css selector','.mi-button.mi-button--primary']
# 商品页面
GoodItemsPage:
first_item: ['css selector','.goods-list.clearfix>div:nth-child(1) a']
# 商品详情页
ItemPage:
buy_btn: ['css selector','.btn.btn-small.btn-primary.J_nav_buy']
# 商品认购页面
BuyPage:
addCart_btn: ['css selector','.sale-btn']
# 购物车页面
ShopCartPage:
check_ele: ['id','J_miniHeaderTitle']
四、TestCase层
from Base.bases import BasePage
import time
# 首页
class IndexPage(BasePage):
def __init__(self, driver):
BasePage.__init__(self, driver)
# 访问小米首页
self.get_url('testUrl','url')
# 进入登录页
def to_login(self):
# 点击小米首页的登录按钮
self.click(*self.login_btn)
# 首页————点击协议声明的同意按钮(注意:这个跳转窗口不一定每次都出现,比如只有第一次才会出现)
self.click_ele_exist(*self.user_proxy)
# 返回登录页对象
return LoginPage(self.driver)
# 搜索商品
def search_item(self, item="小米11"):
# 首页——搜索商品
self.input_text(item+'\n', *self.search_input)
return GoodItemsPage(self.driver)
# 登录页面
class LoginPage(BasePage):
def __init__(self, driver):
BasePage.__init__(self, driver)
# 账户密码登录
def login(self, username ,psw):
# 登录页面————输入登录用户名和密码
self.input_text(username, *self.user_input)
self.input_text(psw, *self.psw_input)
time.sleep(3)
# 登录页面——点击登录按钮
self.driver.find_element(*self.login_btn).click()
return IndexPage(self.driver)
# 商品页面
class GoodItemsPage(BasePage):
def __init__(self, driver):
BasePage.__init__(self, driver)
self.driver = driver
def pick_item(self):
# 产品详情页——选中第一个商品
self.click(*self.first_item)
if self.switch_window('小米11 轻装上阵'):
return ItemPage(self.driver)
# 商品详情页
class ItemPage(BasePage):
def __init__(self, driver):
BasePage.__init__(self, driver)
self.driver = driver
def to_buy(self):
# 详情页面——点击立即认购按钮
self.driver.find_element(*self.buy_btn).click()
if self.switch_window('小米11立即购买-小米商城'):
return BuyPage(self.driver)
# 商品认购页面
class BuyPage(BasePage):
def __init__(self, driver):
BasePage.__init__(self, driver)
self.driver = driver
def add_cart(self):
# 认购页面——点击加入购物车按钮
self.click(*self.addCart_btn)
return ShopCartPage(self.driver)
# 购物车页面
class ShopCartPage(BasePage):
def __init__(self, driver):
BasePage.__init__(self, driver)
self.driver = driver
def check_item(self):
# 检查是否添加购物车成功
res = self.get_text(*self.check_ele)
assert '确认订单' in res
# 如果操作涉及页面跳转——需要返回对应的页面对象,如果没有,则不需要
if __name__ == '__main__':
# 首页——进入登录-首页-搜索商品-商品页面-商品详情页——认购页面-购物车页面
from selenium import webdriver
driver = webdriver.Chrome()
driver.implicitly_wait(10)
IndexPage(driver).to_login().login('15**********','*********').search_item().pick_item().to_buy().add_cart().check_item()
quit()
下面是一个UI流程测试的demo,分层更全面可以参考一下:https://blog.csdn.net/qq_37405087/article/details/117420481?spm=1001.2014.3001.5501