POM设计模式
POM(page object model) 页面对象模型 WEB自动化测试框架应用最为广泛的一种框架设计模式。
设计思路:web项目由很多页面组成,把每个页面当做页面对象来进行设计
Python专题:什么是对象?通过类描述一组对象 对象=属性+方法
电商项目 = n个页面 = 对每个页面设计对应页面类 = 相同属性 + 相同的方法
class LoginPage:
#属性? 元素、页面标题...
#方法? 页面进行操作/行为:点击、定位、输入...等等元素及页面的操作
每个页面有相同的属性及方法 比如:点击、输入、元素定位
基于POM进行设计分为四层进行架构:
第一层: basepage层 每个页面有相同的属性及方法 比如:点击、输入、元素定位
第二层: pageobjects层 针对每个页面定义页面类 每个页面有独有的属性及方法:
登录页面 LoginPage类
注册页面 RegisterPage类
第三层: TestCases层 用例层包含项目的业务流程
第四层: TestData 测试数据
# base/basepage.py import os import time from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from common.logger import FrameLog as log from common import dir_config as Dir class BasePage: """ BasePage:定义每个页面的相同属性及方法 相同属性?获取浏览器驱动对象(数据) 相同方法?元素定位、点击、输入...等等操作 日志 错误截图 测试报告 """ def __init__(self, driver): self.driver = driver def locator(self, page_name, loc, ): """元素定位""" # WebElement对象 try: el = self.driver.find_element(*loc) log().getLogger().info(f"在[{page_name}],定位到元素:{loc}") except: log().getLogger().error(f"在[{page_name}],未定位到元素:{loc}!!!") # 失败截图 self.sava_page_shot(page_name) raise return el # 等待元素存在 def wait_ele_visibility(self, page_name, loc, timeout=15, poll_fre=0.5): try: WebDriverWait(self.driver, timeout, poll_fre).until(EC.visibility_of_element_located(loc)) # WebElement对象 log().getLogger().info(f"在[{page_name}],找到元素:{loc}可见") except: log().getLogger().error(f"在[{page_name}],未找到元素:{loc}可见!!!") # 等待元素可见 def wait_ele_presence(self, page_name, loc, timeout=15, poll_fre=0.5): try: WebDriverWait(self.driver, timeout, poll_fre).until(EC.presence_of_element_located(loc)) log().getLogger().info(f"在[{page_name}],找到元素:{loc}存在") except: log().getLogger().error(f"在[{page_name}],未找到元素:{loc}存在!!!") def input(self, page_name, loc, value): """输入""" # 等待元素可见 try: self.wait_ele_visibility(page_name, loc) self.locator(page_name, loc).send_keys(value) log().getLogger().info(f"在{page_name},元素{loc}输入:{value}!") except: log().getLogger().error(f"在{page_name},元素{loc}输入失败!") # 失败截图 self.sava_page_shot(page_name) def click(self, page_name, loc): """点击""" try: # 等待元素可见 self.wait_ele_visibility(page_name, loc) self.locator(page_name, loc).click() log().getLogger().info(f"在[{page_name}],点击元素{loc}成功!") except: log().getLogger().error(f"在[{page_name}],元素{loc}点击失败!") # 失败截图 self.sava_page_shot(page_name) def sleep(self, s): time.sleep(s) # 鼠标键盘操作 def move_element(self, page_name, loc): try: # 等待元素可见 self.wait_ele_visibility(page_name, loc) ActionChains(self.driver).move_to_element(self.locator(page_name, loc)).perform() log().getLogger().info(f"在[{page_name}],鼠标移动到元素:{loc}") except: log().getLogger().error(f"在[{page_name}],鼠标移动到元素{loc}失败!") # 失败截图 self.sava_page_shot(page_name) def sava_page_shot(self, img_name): filename = os.path.join(Dir.screen_dir, img_name + '.png') self.driver.save_screenshot(filename) log().getLogger().info(f"失败截图,截取当前网页,存储的路径:{filename}") # 日志+错误截图+测试报告输出
# pageobjects/goodspay_page.py import time from selenium.webdriver.common.by import By from base.basepage import BasePage from pagelocations.goodspay_page_locs import GoodsPayLoc as Locs class GoodspayPage(BasePage): """ GoodpayPage:支付页面 """ def select_goods(self, goodsname): # 输入搜索内容 self.input("支付页面", Locs.selectcontent_loc, goodsname) # 点击搜索 self.click("支付页面", Locs.select_loc) self.sleep(1) # 加入购物车 def gointocart(self): # 鼠标移动到商品 self.move_element("支付页面", Locs.goods_loc) # 点击购物车 self.click("支付页面", Locs.addgoodscart_loc) time.sleep(1) # 结算商品 def paygoods(self): # 鼠标移动到购物车结算菜单 self.move_element("支付页面", Locs.mycartmenu_loc) # 点击结算按钮 self.click("支付页面", Locs.allprice_loc) self.sleep(1) def inputpasswd(self, passwd): # 核对购物车商品 self.click("支付页面", Locs.nextsubmit_loc) self.sleep(1) # 输入支付密码 self.input("支付页面", Locs.paypasswd_loc, passwd) # 点击使用 self.click("支付页面", Locs.userpaypasswd_loc) def paymoney(self): self.click("支付页面", Locs.submit_loc) print("完成支付") # 获取支付的状态的信息 def paystateMsg(self): print("取支付的状态的信息") el = self.locator("支付页面", Locs.paystate_loc) return el.text# pageobjects/login_page.py import time from selenium.webdriver.common.by import By from base.basepage import BasePage from pagelocations.login_page_locs import LoginPageLoc as Locs from testdatas import Globle_Datas as GD class LoginPage(BasePage): """ 登录页面类=页面独有的属性及方法 页面独有的属性:页面元素定位 方法:登录页面的操作 """ # url="http://47.107.116.139/shopnc/shop/index.php?act=login&op=index" # 方法 def login(self, usname, passwd): # 实现登录的步骤 self.driver.get(GD.login_url) self.sleep(2) # 输入用户名 self.input(loc=Locs.el_username, value=usname, page_name="登录页面") # 输入密码 self.input(loc=Locs.el_password, value=passwd, page_name="登录页面") # 点击登录 self.click(loc=Locs.el_login, page_name="登录页面") time.sleep(5) def back_login(self): self.driver.get("") el_username = self.driver.find_element() el_passwd = self.driver.find_element() el_username.send_keys("admin") el_passwd.send_keys("msjy123") self.driver.get_cookies() # 输入验证码 time.sleep(8) # 手工输入验证码 # 点击登录 el_login = self.driver.find_element() el_login.click() self.driver.get_cookies() # name/value 添加cookies self.driver.get_cookies() # 绕过验证码登录 def login_nousername(self): self.driver.get("登录地址") # 获取成功登录后的cook信息进行代码添加 self.driver.add_cookie() # self.driver.get(首页地址)
# testcases/test_goods.py import unittest from selenium import webdriver from common.getdatas import Data from pageobjects.goodspay_page import GoodspayPage from pageobjects.login_page import LoginPage class TestGoods(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.datas = Data(key="").datas # 很多用例包含前置条件,当前用例属于关联功能用例 def setUp(self) -> None: self.driver = webdriver.Chrome() loginpage = LoginPage(self.driver) username = self.datas.get("login").get('sucess')[0] passwd = self.datas.get("login").get('sucess')[1] loginpage.login(usname=username, passwd=passwd) def test_goodsPay(self): goodsname = self.datas.get("goodsPay").get("goodsname") passwd = self.datas.get("goodsPay").get("passwd") # 2、走支付流程 goodspage = GoodspayPage(self.driver) # 选择商品 goodspage.select_goods(goodsname) # 加入购物车 goodspage.gointocart() # 结算商品 goodspage.paygoods() # 支付密码, goodspage.inputpasswd(passwd) # 提交订单 goodspage.paymoney() # 断言 验证包含支付成功字符 # 获取支付状态 paystate = goodspage.paystateMsg() self.assertIn("订单支付成功", paystate)# testcases/testcase_login.py import unittest from selenium.webdriver.common.by import By from pageobjects.login_page import LoginPage import time from selenium import webdriver from testdatas import login_datas as ld class TestLogin(unittest.TestCase): def test_login(self): # 实例化对象 self.driver = webdriver.Chrome() loginpage = LoginPage(driver=self.driver) print(ld.sucess[0]) loginpage.login(ld.sucess[0], ld.sucess[1]) loginpage.sleep(2) # 每个用例对应一个.py的文件? 不是这样 # 用例基于模块进行管理 # test_good.py 设计关于这个模块下的所有自动化测试用例
# testdatas/Globle_datas.py # 根路径 base_url = "http://101.34.221.219:8010/" # 登录路径 login_url = base_url + "?s=user/loginInfo.html"# testdatas/login_Datas.py sucess=('laoban',"laoban123")# testdatas/testdatas.yaml baseurl: "http://47.107.116.139/shopnc/shop" login: url: /?s=user/loginInfo.html success: - laoban - laoban123 goodsPay: goodsname: Python全栈自动化 passwd: mashang
# common/dir_config.py import os # 根路径 base_dir=os.path.dirname( os.path.dirname(os.path.abspath(__file__))) # 用例路径 testcases_dir=os.path.join(base_dir,"testcases") # 数据路径 testdatas_dir=os.path.join(base_dir,"testdatas") # 测试报告路径 reports_dir=os.path.join(base_dir,"Outputs/reports") # 日志路径 logs_dir=os.path.join(base_dir,"Outputs/logs") # 失败截图 screen_dir=os.path.join(base_dir,"Outputs/screenshots") # print(base_dir)# common/getdatas.py import yaml import os import jsonpath from common import dir_config as Dir class Data: def __init__(self, key=None, filename="testdatas.yaml"): filepath = os.path.join(Dir.testdatas_dir, filename) with open(filepath, encoding="utf-8") as yaml_file: self.datas = yaml.load(yaml_file, Loader=yaml.FullLoader) if key: self.data = jsonpath.jsonpath(self.datas, f"$..{key}", ) if __name__ == '__main__': print(Data().datas)# common/logger.py import logging from common import dir_config as Dir import os import time class FrameLog: def getLogger(self): # 创建日志器 logger = logging.getLogger("logger") # 日志输出当前级别及以上级别的信息,默认日志输出最低级别是warning if not logger.handlers: logger.setLevel(logging.INFO) # 创建控制台处理器----》输出控制台 SH = logging.StreamHandler() # 创建文件处理器----》输出文件 logpath = os.path.join(Dir.logs_dir, f"log_{time.strftime('%Y%m%d%H%M%S', time.localtime())}.txt") FH = logging.FileHandler(logpath) # 日志包含哪些内容 时间 文件 日志级别 :事件描述/问题描述 formatter = logging.Formatter(fmt="[%(asctime)s] [%(filename)s] %(levelname)s :%(message)s", datefmt='%Y/%m/%d %H:%M:%S') logger.addHandler(SH) logger.addHandler(FH) SH.setFormatter(formatter) FH.setFormatter(formatter) return logger def sum(self, a, b): sum = a + b self.getLogger().info(f"实现求和:{sum}") return sum if __name__ == '__main__': FrameLog().sum(1, 2) # 调试代码
# pagelocations/goodspay_page_locs.py from selenium.webdriver.common.by import By class GoodsPayLoc: # 属性:元素定位 # 搜索内容框 selectcontent_loc=(By.XPATH,"//input[@id='keyword']") # 搜索按钮 select_loc=(By.ID,"button") # 商品 goods_loc=(By.XPATH,"//div[@class='goods-name']/a") #加入购物车按钮 addgoodscart_loc=(By.XPATH,"//div[@class='add-cart']/a") #购物车结算菜单 mycartmenu_loc=(By.XPATH,"//div[@class='head-user-menu']/dl[@class='my-cart']/dt") # 结算按钮 allprice_loc=(By.XPATH,"//div[@class='checkout']/a") # 核对购物车商品 nextsubmit_loc=(By.XPATH,"//div[@class='ncc-bottom']/a") # 支付密码框定位语句 paypasswd_loc = (By.XPATH, "//input[@id='password']") #使用按钮 userpaypasswd_loc=(By.XPATH,"//div[@id='pd_password']/a") #提交订单 submit_loc = (By.XPATH, "//div[@class='ncc-bottom']/a") # 订单状态 paystate_loc=(By.XPATH,"//div[@class='ncc-finish-a']")# pagelocations/login_page_locs.py from selenium.webdriver.common.by import By class LoginPageLoc: # 登录页面的属性 el_username = (By.NAME, "accounts") el_password = (By.NAME, "pwd") el_login = (By.XPATH, "//form[@class='am-form form-validation-username']/div[3]/button")
# run.py import os import unittest from HTMLTestRunner import HTMLTestRunner from common import dir_config as Dir import time # 加载用例集 testcases = unittest.defaultTestLoader.discover(Dir.testcases_dir, 'test*.py') reportpath = os.path.join(Dir.reports_dir, f"{time.strftime('%Y%m%d%H%M%S', time.localtime())}_rport.html") with open(reportpath, "wb+") as htmlf: HTMLTestRunner(stream=htmlf, title="测试报告").run(testcases) # 执行用例,生产测试报告