当前位置: 首页 > news >正文

关于Selenium的网页对象单元测试的设计模式

写在前面:经过了实践总结一下经验,心得进行一个分享。


首先driver是可以单独抽出来的,变成一个driver函数放在driver.py。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Optionsdef get_chrome_driver():# 启动driveroptions = Options()# 替换为你本地的Chromed路径options.binary_location = r"D:\software\Chrome-bin\chrome.exe"# 替换为你本地的Chromedriver路径chromedriver_path = r'D:\software\Chrome-bin\chromedriver.exe'# 使用Service对象指定Chromedriver路径service = Service(chromedriver_path)driver = webdriver.Chrome(service=service, options=options)return driver

然后我们新建page.py,在这里我们只处理页面的对象,因此我们创建页面类在此,当然这个页面类需要和HTML元素和驱动进行组合才能形成一个页面。

我们创建BasePage,以后的页面类都用它作为基类。首先是传一个驱动,组合起来

class BasePage(object):"""Base class to initialize the base page that will be called from allpages"""def __init__(self, driver):self.driver = driverclass LoginPage(BasePage):def __init__(self, driver):super().__init__(driver)

接着我们在element.py创建元素的基类,以后的元素类都继承自它

from selenium.webdriver.support.ui import WebDriverWaitclass BaseElement(object):"""Base page class that is initialized on every page object class."""locator = Nonedef __set__(self, obj, value):"""Sets the text to the value supplied"""driver = obj.driverWebDriverWait(driver, 5).until(lambda dri: dri.find_element(*self.locator))driver.find_element(*self.locator).clear()driver.find_element(*self.locator).send_keys(value)def __get__(self, obj, owner):"""Gets the specified element object"""driver = obj.driverWebDriverWait(driver, 5).until(lambda dri: dri.find_element(*self.locator))self.element = driver.find_element(*self.locator)return self.elementdef click(self):self.element.click()def get_text(self):return self.element.get_attribute("value")

接着我们在locator.py创建定位器类,没什么特别,就是作为一个类似字典的静态类存放元素的位置

from selenium.webdriver.common.by import Byclass LonginPageLocators(object):"""A class for login page locators. All login page locators should come here"""basic_username = (By.ID, 'basic_username')basic_password = (By.ID, 'basic_password')details_button = (By.ID, 'details-button')proceed_link = (By.ID, 'proceed-link')login_button = (By.ID, 'submitBtn')

准备工作就绪,那么我们来编写LoginPage吧~
首先组合我们需要的HTML元素,然后编写一个login业务函数进行业务处理。


class BasePage(object):"""Base class to initialize the base page that will be called from allpages"""def __init__(self, driver):self.driver = driverclass LoginPage(BasePage):def __init__(self, driver):super().__init__(driver)class DetailButtonElement(BaseElement):locator = LonginPageLocators.details_buttonclass ProceedLinkElement(BaseElement):locator = LonginPageLocators.proceed_linkclass UsernameTextElement(BaseElement):locator = LonginPageLocators.basic_usernameclass PasswordTextElement(BaseElement):locator = LonginPageLocators.basic_passwordclass LoginButtonElement(BaseElement):locator = LonginPageLocators.login_buttonclass RankBoxElement(BaseElement):locator = LonginPageLocators.rank_boxdetail_button_ele = DetailButtonElement()proceed_link_ele = ProceedLinkElement()username_text_ele = UsernameTextElement()password_text_ele = PasswordTextElement()login_button_ele = LoginButtonElement()rank_box_ele = RankBoxElement()def login(self):self.detail_button_ele.click()self.proceed_link_ele.click()self.username_text_ele = 'admin'self.password_text_ele = '123456'self.login_button_ele.click()_ = self.rank_box_ele  # just test web is complete

_ = self.rank_box_ele小细节是用来测试是否进入主页面的。

回到单元测试.py添加测试函数,debug运行。

    def test_login(self):login_page = page.LoginPage(self.driver)login_page.login()

当我们登录成功后,我们就可以跳转到我们需要页面,进行脚本处理。当然了进入了新的页面,别忘了创建新的页面类。在我的例子中就是创建了新的页面类ResourceDetailPage以便完成后续的业务。

    def test_turn_to_resource(self):self.test_login()# 页面跳转self.driver.get("https://127.0.0.1:38000/#/resource/detail/3668")def test_resource_delete(self):self.test_turn_to_resource()# 创建新的page对象resource_detail_page = page.ResourceDetailPage(self.driver)# 在新的page处理业务...resource_detail_page.while_delete()

相关文章:

  • 深度学习 | ModernTCN模型结构
  • Linux虚拟文件系统
  • Unity关于动画混合树(Blend Tree)的使用
  • Chocolatey
  • 手机上的软件怎么修改网络IP地址
  • 学习笔记13——Spring整合Mybatis、junit、AOP、事务
  • Web前端框架全景:流行选择与技术趋势
  • Java集合/泛型篇----第三篇
  • react中的类(有状态)组件,函数(无状态)组件·示例,对比及组件样式引用方案(附代码)
  • springBoot2.3-基本介绍及入门案例
  • CDH 6.3.2集成flink 1.18 zookeeper版本不匹配Flink-yarn启动失败
  • 通信原理课设(gec6818) 007:语音识别
  • 【算法题】30. 串联所有单词的子串
  • 如何使用ArcGIS Pro将Excel表转换为SHP文件
  • 14.用户管理
  • “大数据应用场景”之隔壁老王(连载四)
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • canvas 五子棋游戏
  • create-react-app项目添加less配置
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • es6(二):字符串的扩展
  • Hibernate【inverse和cascade属性】知识要点
  • input实现文字超出省略号功能
  • JavaScript创建对象的四种方式
  • Magento 1.x 中文订单打印乱码
  • MySQL主从复制读写分离及奇怪的问题
  • npx命令介绍
  • win10下安装mysql5.7
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 小程序开发中的那些坑
  • 一个项目push到多个远程Git仓库
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • Spring第一个helloWorld
  • 第二十章:异步和文件I/O.(二十三)
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (007)XHTML文档之标题——h1~h6
  • (C)一些题4
  • (C语言)逆序输出字符串
  • (差分)胡桃爱原石
  • (定时器/计数器)中断系统(详解与使用)
  • (二)pulsar安装在独立的docker中,python测试
  • (二)斐波那契Fabonacci函数
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • ***通过什么方式***网吧
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .NET中winform传递参数至Url并获得返回值或文件
  • .so文件(linux系统)
  • [100天算法】-不同路径 III(day 73)
  • [20181219]script使用小技巧.txt
  • [AIGC] Nacos:一个简单 yet powerful 的配置中心和服务注册中心
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt