1.任何元素操作之前一定要等待,操作任何一个元素之前都要等到它出现,然后再去操作它,否则会遇到报错,元素找不到。页面的某一个操作导致页面发生变化的时候,就必须要等,等到元素出现,再去使用。
2.一个用例执行失败,但是整个运行过程不应该结束。所以,放在其它服务器上,我们分析问题的时候需要日志和测试报告。自动生成测试报告以及执行日志。执行日志需要打印出来,里面每一点每一点都在干什么。如果有报错,错误信息也应该显示在日志里面。Web自动化涉及页面操作,如果有报错,还需要有截图。通过看截图可以看到问题在哪。
比如login用例中的每一步是页面对象的方法来执行的,要保证任何一行代码执行失败,都能找到这样一个报错并截图,以及对应的报错信息放在日志中。异常需要抛出,它失败了,意味着测试用例失败了。
3.在每个页面对象的每一个方法中都加try except,用例的断言加try except,但是这样很冗余,我们怎样更好得解决呢?
在自己的业务函数中调用的都是selenium webdriver中的基本函数。大部分的操作都是等待、点击、输入,当然还有下拉列表处理、窗口处理等等,既然所有的方法都是基于这些基本操作。
对click() find_element wait .text get_attribute,先单独对这些函数都做一些异常处理,对这些基本函数都做到了异常处理日志输出,所有这些地方来调用它的都能做到了。
4.basepage可以放一些公共的方法。
basepage对日志、异常处理、截图进行了处理。
5.希望看到这个截图的时候,一看就知道是哪个页面,哪个地方截的图。如果所有的截图文件都是一个名字,那看到的只有最后一次截图,其它都被覆盖了。框架当中要截图,图片名称要非常得到位就行。
6.save_screenshot是有截屏操作的。只截图浏览器当中当前页面的内容,浏览器以外的内容都截图不了。比如上传窗口就是截图不到的。通过按键方式进行全屏截取,Python库中也有截取整个屏幕的函数调用。
这里只用截取html页面就行了。看save_screenshot的源码解释:
return self.get_screenshot_as_file(filename)
就是存储为文件的意思。
6.是基本操作会来调用截屏。在页面的某一个具体操作行为当中才会调用等待。wait_eleVisible知道到底当前是哪个模块,哪个页面,哪个操作。谁调它,谁就传值。所以需要传递一个参数,把这个参数给到截屏。
7.实际过程中,你自己写的框架,理论上来说只适用于当前你的项目的,项目的差异性是非常大的。如果别人问你,你的框架有什么可以改进的空间?只能说目前做的框架对以前的项目是完全够用的,未来在工作过程中遇到什么问题,再去考虑扩展。
8.断言中没有做异常捕获,不捕获也没关系,断言失败的详情会在测试日志中体现的比较明显。
来自Common文件夹下的basepage.py文件
from Common import logger
import logging
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import datetime
import time
from Common.dir_config import screenshot_dir
class BasePage:
# 包含了PageObjects当中,用到所有的selenium底层方法。
# 还可以包含通用的一些元素操作,如alert,iframe,windows...
# 还可以自己额外封装一些web相关的断言
# 实现日志记录、实现失败截图
def __init__(self,driver):
self.driver = driver
def wait_eleVisible(self,loc,img_doc="",timeout=30,frequency=0.5):
logging.info("等待元素 {} 可见。".format(loc))
try:
# 起始等待的时间 datetime
start = datetime.datetime.now()
WebDriverWait(self.driver,timeout,frequency).until(EC.visibility_of_element_located(loc))
# 结束等待的时间
end = datetime.datetime.now()
logging.info("开始等待时间点:{},结束等待时间点:{},等待时长为:{}".
format(start,end,end-start))
except:
# 日志
logging.exception("等待元素可见失败:")
# 截图 - 哪一个页面哪一个操作导致的失败。+ 当前时间
self.save_web_screenshot(img_doc)
raise
# 查找一个元素
def get_element(self,loc,img_doc=""):
"""
:param loc: 元素定位。以元组的形式。(定位类型、定位时间)
:param img_doc: 截图的说明。例如:登陆页面_输入用户名
:return: WebElement对象。
"""
logging.info("查找 {} 中的元素 {} ".format(img_doc,loc))
try:
ele = self.driver.find_element(*loc)
return ele
except:
# 日志
logging.exception("查找元素失败")
# 截图
self.save_web_screenshot(img_doc)
raise
def click_element(self,loc,img_doc,timeout=30,frequency=0.5):
"""
实现了,等待元素可见,找元素,然后再去点击元素。
:param loc:
:param img_doc:
:return:
"""
# 1、等待元素可见
self.wait_eleVisible(loc,img_doc,timeout,frequency)
# 2、找元素
ele = self.get_element(loc,img_doc)
# 3、再操作
logging.info(" 点击元素 {}".format(loc))
try:
ele.click()
except:
# 日志
logging.exception("点击元素失败")
# 截图
self.save_web_screenshot(img_doc)
raise
# 文本输入
def input_text(self,loc,img_doc,*args):
# 1、等待元素可见
self.wait_eleVisible(loc,img_doc)
# 2、找元素
ele = self.get_element(loc,img_doc)
# 3、再操作
logging.info(" 给元素 {} 输入文本内容:{}".format(loc,args))
try:
ele.send_keys(*args)
except:
# 日志
logging.exception("元素输入操作失败")
# 截图
self.save_web_screenshot(img_doc)
raise
# 获取元素的属性值
def get_element_attribute(self,loc,attr_name,img_doc):
ele = self.get_element(loc,img_doc)
# 获取属性
try:
attr_value = ele.get_attribute(attr_name)
logging.info("获取元素 {} 的属性 {} 值为:{}".format(loc, attr_name,attr_value))
return attr_value
except:
# 日志
logging.exception("获取元素属性失败")
# 截图
self.save_web_screenshot(img_doc)
raise
# 获取元素的文本值。
def get_element_text(self,loc,img_doc):
ele = self.get_element(loc, img_doc)
# 获取属性
try:
text = ele.text
logging.info("获取元素 {} 的文件值为:{}".format(loc, text))
return text
except:
# 日志
logging.exception("获取元素文本值失败")
# 截图
self.save_web_screenshot(img_doc)
raise
# 实现网页截图操作
def save_web_screenshot(self,img_doc):
# 页面_功能_时间.png
now = time.strftime("%Y-%m-%d %H_%M_%S")
filepath = "{}_{}.png".format(img_doc,now)
try:
self.driver.save_screenshot(screenshot_dir +"/" + filepath)
logging.info("网页截图成功。图片存储在:{}".format(screenshot_dir +"/" + filepath))
except:
logging.exception("网页截屏失败!")
# windows切换
# iframe切换
# select下拉列表
# 上传操作 -
PageObjects文件夹下的index_page.py文件
from Common.basepage import BasePage
from PageLocators.indexPage_locator import IndexPageLocator as loc
import time
class IndexPage(BasePage):
# 检测昵称是否存在
def check_nick_name_exists(self):
"""
:return: 存在返回True,不存在返回False
"""
self.wait_eleVisible(loc.about_us,"首页_等待关于我们元素出现")
time.sleep(0.5)
try:
self.get_element(loc.user_link,"首页_找用户昵称元素")
return True
except:
return False
# 点击投标按钮
def click_invest_button(self):
self.click_element(loc.bid_button,"首页_点击第一个抢投标按钮")
PageObjects文件夹下的bid_page.py文件
from PageLocators.bidPage_locator import BidPageLocator as loc
from Common.basepage import BasePage
class BidPage(BasePage):
# 投资
def invest(self,money):
# 在输入框当中,输入金额
self.input_text(loc.money_input,"标页面_金额输入框",money)
self.click_element(loc.invest_button,"标页面_提交投资操作")
# 获取用户余额
def get_user_money(self):
self.wait_eleVisible(loc.money_input,"标页面_获取用户余额")
return self.get_element_attribute(loc.money_input,"data-amount","标页面_获取用户余额")
# 投资成功的提示框 - 点击查看并激活
def click_activeButton_on_success_popup(self):
self.click_element(loc.active_button_on_successPop,"标页面_投资成功的提示框 - 点击查看并激活")
# 错误提示框 - 页面中间
def get_errorMsg_from_pageCenter(self):
self.wait_eleVisible(loc.invest_failed_popup,"标页面_投资失败提示框 - 提示信息获取")
msg = self.get_element_text(loc.invest_failed_popup,"标页面_投资失败提示框 - 提示信息获取")
self.click_element(loc.invest_close_failed_popup_button,"标页面_关闭投资失败提示框")
return msg
# 获取提示信息 - 投标按钮上的
def get_errorMsg_from_investButton(self):
pass
