知方号

知方号

web自动化实战之BasePage

web自动化实战之BasePage

什么是BasePage?

到目前为止,我们已经封装了四个PO:login_page、index_page、 invest_page和user_page。在这些PO当中,存在着很多重复使用的方法,比如访问页面、等待页面标题出现、find_element、各种等待等。其实这些方法我们都可以单独拉出来封装到一个模块中,然后供所有的PO调用。这种把每个PO的通用方法单独拉出来封装成到一个公共类当中的思想就叫做BasePage。

页面行为分类

页面行为分为两类:

业务型页面行为 。这类行为是这个页面会用得到,换了另一个页面就用不上。比如说index_page中的抢投标操作: 这种行为只在首页能用到,因为只有首页需要进行抢投标的操作,而换成其他页面,比如说登录页,就用不到这种操作了。通用型页面行为。这类行为是所有的页面甚至所有项目都有可能会用到的行为。比如说通过url访问页面、等待元素可见,在登录页面用得到,在别的任何页面都可能用得到,甚至换个项目,这个项目下的任何页面都会用得上。像这一类通用的页面行为就可以封装到basepage当中。 哪些页面行为可以被封装成basepage? 访问页面。根据所给的url访问对应页面;各类显性等待。如:等待页面标题出现、等待元素可见、等待元素可被点击、等待元素被加载到dom树中;各类元素操作。如:点击、输入字符、滚动、移动到某个元素、选择select下拉框等;三大切换。包括:iframe切换、窗口切换、alert切换;文件上传;js操作。如改变页面元素的属性、窗口滚动等;页面截屏。当执行出现错误时截图。 代码实战 basepage放到哪?

basepage放到哪比较合适呢?无非就两个:middleware、common。middleware是当前项目中通用的,而common是换了个项目也还能用的。很显然,basepage并不只是当前项目通用,所以放到common中比较合适。

basepage.py import osfrom datetime import datetimefrom selenium.webdriver import ActionChainsfrom selenium.webdriver.support import expected_conditionsfrom selenium.webdriver.support.wait import WebDriverWaitfrom config import configfrom middleware.handler import Handlerclass BasePage: title = None def __init__(self, driver): self.driver = driver #等待页面标题出现 try: WebDriverWait(self.driver, 20).until( expected_conditions.title_contains(self.title) ) except: print("你的操作可能不在当前页面中,可能会引发异常{}".format(self.title))#查找元素 def find_element(self, locator): try: el = self.driver.find_element(*locator) return el except: # 如果找不到元素,截图 self.screen_shot() Handler.logger.error("元素找不到:{}".format(locator))#元素找不到时截图 def screen_shot(self): path = config.IMG_PATH ts = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") filename = os.path.join(path, ts + ".png") self.driver.save_screenshot(filename)#等待元素可见 def wait_element_visible(self, locator, timeout=20, poll=0.5): try: el = WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll).until( expected_conditions.visibility_of_element_located(locator) ) return el except: self.screen_shot() Handler.logger.error("元素找不到{}".format(locator))#等待元素可被点击 def wait_element_clickable(self, locator, timeout=20, poll=0.5): try: el = WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll).until( expected_conditions.element_to_be_clickable(locator) ) return el except: self.screen_shot() Handler.logger.error("元素找不到{}".format(locator))#等待元素被加载 def wait_element_presence(self, locator, timeout=20, poll=0.5): try: el = WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll).until( expected_conditions.presence_of_element_located(locator) ) return el except: self.screen_shot() Handler.logger.error("元素找不到{}".format(locator))#点击元素 def click(self, locator): #当元素可被点击时再点击 self.wait_element_clickable(locator).click() return self#输入字符 def write(self, locator, value='): #当元素被加载出来时再输入字符 self.wait_element_presence(locator).send_keys(value) return self#窗口滚动 def scroll(self, height=None, width=None): if not height: height = 0 if not width: width = 0 js_code = "window.scrollTo({}, {});".format(width, height) self.driver.execute_script(js_code) return self#移动到某个元素上面 def move_to(self, locator): el = self.driver.find_element(*locator) ActionChains(self.driver).move_to_element(el).perform() return self #iframe切换 def switch_frame(self, locator, timeout=20): WebDriverWait(self.driver, timeout=timeout).until( expected_conditions.frame_to_be_available_and_switch_to_it(locator) ) return self

在这里说明几点:

元素操作前的等待。在进行元素操作前,最好要事先想想要不要加显性等待,很多情况下元素操作前没加等待的话可能会出现异常,比如说跳转至下一个页面,元素还没见到就去定位这个元素并点击,这自然是会出错的。所以这里在点击元素、输入字符时都增加了相应的等待;窗口滚动。这里窗口滚动是直接用javascript脚本实现。当height未传或传了None,则把高度设为0,也就是不进行纵向滚动;当width未传或传了None,则把宽度设为0,也就是不进行横向滚动;无论是报告还是截图,亦或是其他的文件,一般都会做两件事:一个是放到某个目录下,另一个是文件名以时间戳方式命名,方便查找和定位。规定文件放到某个目录下,需要调用os.path的join进行目录与项目路径的拼接,形成新路径,这个路径一般放到config目录当中;以时间戳方式命名文件一般需要调用datetime.now().strftime(),调用现在的时间并以特定格式显示,需要在strfime中传入格式的样式;标题变量的位置。这里title变量不宜放到初始化方法当中,因为这样在测试方法中调用PO时都需要传入页面标题,很不好,所以应作为类方法出现,这样每个PO下都能自行定义各自的标题。 pageobject继承basepage

basepage写好了,那么怎么给每个po类进行调用呢?像这种定好了一个模板,其他类都需要用到这个模板的场景应该用继承。

login_page.py from config import configfrom middleware.page.index_page import Index_pagefrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support import expected_conditionsfrom common import basepageclass Login_page(basepage.BasePage): title = "前程贷官网 - 欢迎登录" url = config.HOST + "/Index/login.html" def __init__(self,driver): self.driver = driver #元素定位(定位方法+定位表达式) login_btn_locator = (By.CLASS_NAME, "btn-special") username_locator = (By.NAME, "phone") pwd_locator = (By.NAME, "password") error_msg_locator = (By.CLASS_NAME, "form-error-info") invalid_msg_locator = (By.CLASS_NAME, "layui-layer-content") def get_url(self): self.driver.get(self.url) return self #登录失败 def login_failed(self,username,password): # 元素定位、元素操作(定位用户名、密码并输入,点击登录) self.enter_username(username) self.enter_password(password) self.click_login_button() return self #登录成功 def login_success(self,username,password): # 元素定位、元素操作(定位用户名、密码并输入,点击登录) self.enter_username(username) self.enter_password(password) self.click_login_button() return Index_page(self.driver) #登录未授权用户 def login_invaild(self,username,password): #元素定位、元素操作(定位用户名、密码并输入,点击登录) self.enter_username(username) self.enter_password(password) self.click_login_button() return self #输入用户名 def enter_username(self,username): self.write(self.username_locator,username) return self #输入密码 def enter_password(self,password): self.write(self.pwd_locator,password) return self #点击登录按钮 def click_login_button(self): self.click(self.login_btn_locator) return self #用户名、密码为空时获取错误信息 def get_error_message(self): error_text = self.find_element(self.error_msg_locator).text return error_text #用户未授权时获取错误信息 def get_invaild_message(self): invaild_locator = self.find_element(self.invalid_msg_locator).text return invaild_locator

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。