UI自动化测试 selenium:是WEB的UI测试框架,可以和主流的编程语言(Python,Java,Net,PHP,JavaScript)整合来测试WEB系统,同时也是支持主流的浏览器(IE,Firefox,Chrome)。 Selenium通过driver的驱动方式来操作浏览器,对浏览器进行各种交互式的验证(点击,输入,下拉框选项。。。)
看了无涯老师的博客整理的非常通俗易懂:
一、UI自动化测试
1、为什么要学习UI自动化测试
在学习自动化测试之前,需要考虑我们为什么要学习自动化测试,以及今天业界谈的研发效能对测试而言意味着什么?其实这就需要在测试以及整体研发的角度来思考这个问题,在当下这样的市场环境中,打造高质量的持续交付产品质量,基本是所有互联网研发团队和测试团队都追求的一个方向。在敏捷流行的今天,以及新的技术在企业全面的落地,在测试而言,就需要通过测试技术的手段以及质量管理的思维能力来提升测试效率和交付满足市场期待的产品质量。
自动化测试基础是所有测试形式里面就目前而言,是最基础的也是最核心的,因为自动化测试连接了功能测试以及高阶测试开发的测试技术栈的知识体系。
即使初级测试员也得具备自动化测试得思维能力和技术能力。
2、UI自动化测试得必要性
与API自动化测试相比较,UI自动化测试不论是从执行效率上还是编程难易度上都比API自动化测试要好,相比较API自动化测试地成本是比较高的,如果单纯的从技术复杂度上来说:UI与API的测试技术栈的体系都是一样的,不同的是:测试的思维以及背后的思想。但是还需要比较清楚的是:UI自动化测试在DevOps的体系以及测试流水线上它是非常必要的,只不过我们需要使用更加正确的姿势来利用好这个技术,比如使用它来验证核心的流程,而抛开更多的非主线的业务。不能简单的说它的测试执行效率低,就完全的否定UI自动化测试的价值,这样是很不理性的。在主流的UI自动化测试框架中,Selenium经过多年的发展,他的技术体系以及生态体系都是非常完善的,能够得到各大主流浏览器厂商的支持,和完善的document文档,以及与各个编程语言之间的兼容。
二、元素属性操作
在UI自动化测试中,最核心的基础就是需要定位到元素的属性 ,然后就可以针对这个属性进行具体的相关页面交互操作,比如进行关键字的输入, 以及点击的操作等。
selenium3的源码体系,而元素的方法来自by模块中的by类,如下是具体源码:
class By(object): """ Set of supported locator strategies. """ ID = "id" XPATH = "xpath" LINK_TEXT = "link text" PARTIAL_LINK_TEXT = "partial link text" NAME = "name" TAG_NAME = "tag name" CLASS_NAME = "class name" CSS_SELECTOR = "css selector"
从by类中可以看到元素的定位方式有8种,在上面显示的非常详细,但是针对元素具体的方法都是在webdriver的模块里面,这些方法都在该模块里面。
从元素分类的角度而言,元素定位可以分为单个元素定位和多个元素定位,那么也就是单个元素的方法有8种,多个元素的定位方法也是8种,总共16种方法。
针对单个元素代码如下:
def find_element(self, by=By.ID, value=None) -> WebElement: """ Find an element given a By strategy and locator. :Usage: :: element = driver.find_element(By.ID, 'foo') :rtype: WebElement """ if by == By.ID: by = By.CSS_SELECTOR value = '[id="%s"]' % value elif by == By.TAG_NAME: by = By.CSS_SELECTOR elif by == By.CLASS_NAME: by = By.CSS_SELECTOR value = ".%s" % value elif by == By.NAME: by = By.CSS_SELECTOR value = '[name="%s"]' % value return self.execute(Command.FIND_ELEMENT, { 'using': by, 'value': value})['value'] def find_elements(self, by=By.ID, value=None) -> List[WebElement]: """ Find elements given a By strategy and locator. :Usage: :: elements = driver.find_elements(By.CLASS_NAME, 'foo') :rtype: list of WebElement """ if isinstance(by, RelativeBy): _pkg = '.'.join(__name__.split('.')[:-1]) raw_function = pkgutil.get_data(_pkg, 'findElements.js').decode('utf8') find_element_js = "return ({}).apply(null, arguments);".format(raw_function) return self.execute_script(find_element_js, by.to_dict()) if by == By.ID: by = By.CSS_SELECTOR value = '[id="%s"]' % value elif by == By.TAG_NAME: by = By.CSS_SELECTOR elif by == By.CLASS_NAME: by = By.CSS_SELECTOR value = ".%s" % value elif by == By.NAME: by = By.CSS_SELECTOR value = '[name="%s"]' % value # Return empty list if driver returns null # See https://github.com/SeleniumHQ/selenium/issues/4555 return self.execute(Command.FIND_ELEMENTS, { 'using': by, 'value': value})['value'] or []
三、常用元素定位实战
1、单个元素
1.1、find_element_by_id
find_element_by_id()的方法主要指的是我们定位元素属性主要是以ID的方式来进行定位,ID一般都是唯一的,有时开发为了保持这种唯一性,使用了动态ID的方式:解决思路也非常简单,那就是XPATH的解决思路了。这地方还是聚焦于ID的属性定位方式,百度搜索输入框的ID源码为:
<input id='kw' name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
这是百度搜索输入框 input 输入框的源代码部分,从源代码我们就可以得到它的ID是kw ,下面是结合具体的代码进行操作:
from selenium import webdriver
import time as t
# 实例化webdriver,并且指定要测试的浏览器 driver=webdriver.Chrome() # 打开浏览器后导航到百度 driver.get('https://www.baidu.com') # send keys 是输入的方法(通过ID属性定位到百度的搜索输入框,并且输入搜索的关键字) driver.find_element(By.ID,'kw').send_keys('QQ异常') # 时间停滞三秒 t.sleep(3) # 退出浏览器 driver.quit()
1.2、find_element_by_name
下面是以name的属性来进行定位和具体的操作,还是从上面的源码得到它的name为wd,调用的方法当然都是find_element_by_name()的方法,按照name的属性
在搜索输入框输入搜索关键字的测试案例如下
'''class name''' from selenium import webdriver import time as t # driver=webdriver.Chrome() # driver.get('https://www.baidu.com') # driver.find_element_by_name('wd').send_keys('接口测试') # t.sleep(3) # driver.quit()
1.3、find_element_by_class_name
下面是class的属性,它使用到的方法是find_element_by_class_name的方式来进行,在属性里面也就是class,以及从上面源码中知道,它的class为s_ipt,
下面实现以class的方式来进行测试代码:
from selenium import webdriver import time as t driver=webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_class_name('s_ipt').send_keys('接口测试') t.sleep(3) driver.quit()
1.4、find_element_by_xpath
当一个元素实在定位不到的时候,也就是id,name,class都不可以的时候,可以使用xpath或者是css的模式,一般推荐xpath的方式,获取元素属性的xpath获取:
1.鼠标找到需要元素的属性
2.右键,点击copy,如下图所示:
3、点击Copy后,选择Copy Xpath,如下图所示:
如果是动态的ID,获取到的xpath也是错误的,那么这个时候怎么解决问题了? 解决思路:点击copy full xpath,这样获取的是xpathde绝对路径,就不会因为动态ID而导致错误。下面还是以百度搜索输入框,获取到它的xpath为://*[@id="kw"],下面具体显示实战代码:
from selenium import webdriver import time as t driver=webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_xpath('//*[@id="kw"]').send_keys('接口测试') t.sleep(3) driver.quit()
1.5 find_element_by_css_selector
使用css的定位操作方式与xpath的操作步骤都是一样的,只不过有点区别的是点击copy后,需要点击的是copy selector,具体如下图:
调用的方法为find_element_by_css_selector, 百度搜索输入框获取到它的css为#kw,那么就以css的方式来演示这部分的测试实战代码,代码如下:
from selenium import webdriver import time as t driver=webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_css_selector('#kw').send_keys('接口测试') t.sleep(3) driver.quit()
1.6、find_element_by_link_text
在页面的交互中,如果存在超链接则可以使用的方法为find_element_by_link_text,比如在百度首先我们需要点击新闻,那么就可以使用这个方法来定位。一般而言在 a 标签里面的,我们都可以理解为超链接,就可以使用该方法来进行具体的操作,针对点击新闻的超链接测试代码为:
from selenium import webdriver import time as t driver=webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_link_text('新闻').click() t.sleep(3) driver.quit()
1.7、find_element_by_paratial_link_text
针对超链接定位还有另一种方法就是find_element_by_partial_link_text,那么把它可以理解为针对超链接的定位方式,不过它可以使用模糊匹配的原则,比如点击视频,我们只可以使用一个关键字“频”,下面还是点击新闻的超链接,但是使用模糊的方式,测试代码如下:
''' LINK_TEXT = "link text" #定位超链接标签(只能使用精准的匹配) PARTIAL_LINK_TEXT = "partial link text" #定位超链接标签(可以使用精准或模糊匹配, 如果使用模糊匹配最好能使用可以唯一关键字;如果有多个值,默认返回第一个值。) ''' driver=webdriver.Chrome() driver.get('https://www.baidu.com') # driver.find_element_by_link_text('视频').click() driver.find_element_by_partial_link_text('频').click() t.sleep(3) driver.quit()
1.8、find_element_by_tag_name
tag_name可以理解为是标签,例如:百度搜索输入框,它的标签是input,那么针对这种我们可以使用标签的方式来进行,使用到的方法
是find_element_by_tag_name,测试实战代码如下:
'''tag_name'''
from selenium import webdriver import time as t
driver=webdriver.Chrome() driver.get('https://www.baidu.com') driver.find_element_by_tag_name('input').send_keys('接口测试') t.sleep(4) driver.quit()
出现问题仔细看看错误信息,我们是能够独立的解决问题的,出现这个问题说明元素定位找不到,导致错误,那么有可能是定位到的元
素属性是错误,还有一种是我们需要索引的方式来解决。如果是后者,是单个元素定位的方式无法解决的,就是多个元素可以解决的了。
2.1、多个元素
针对单个元素定位无法解决的问题,主要核心点是:获取到的元素属性都一样。比如以百度搜索输入框为例,我们使用的是input标签的方式进行,但是input标签有8个,那么就不是唯一的,具体如下所示:
针对这种不是唯一的,我们可以使用多个元素定位的方式来解决,多个元素定位的核心思想是:获取到的元素属性是一个列表,可以使用列表的索引来进行定位,比如针对标签的方法就是find_elements_by_tag_name(),当然其他的方法其实都是一样的,先获取到它的属性,然后输出,就可以看到它的数据是列表,具体案例代码如下:
from selenium import webdriver import time as t driver=webdriver.Chrome() driver.get('http://www.baidu.com') so=driver.find_elements_by_tag_name('input') print(type(so)) t.sleep(3) driver.quit()
因为我们定位的百度搜素输入框的input是在第八位,那么它的索引就是7,那么针对这部分的操作可以调整下代码,修改后的代码为:
from selenium import webdriver import time as t driver=webdriver.Chrome() driver.get('http://www.baidu.com') so=driver.find_elements_by_tag_name('input') so[7].send_keys('接口测试') t.sleep(3) driver.quit()
四、函数式思维
Python是函数式的编程语言,也是面向对象的编程,什么是函数?函数来自数学的思想,模块化的组织思维和把复杂问题简单化的结构化的思维方式,通俗的理解就是把一组语句的集合通过一个函数名封装起来,要想执行这个函数,只需要调用这个函数名就可以了。函数的优势可以总结为:
-
-
程序变得可扩展
-
根据函数式的思想,可以针对元素定位的方法 进行封装,这样调用起来会更加简单,其实 只所以要封装的思考点是:一是利用函数的结构化的思想,二是让调用的方法更加简洁,如下是常有方法的封装,具体如下:
from selenium import webdriver import time as t def findID(driver,ID): return driver.find_element_by_id(ID) def findName(driver,name): return driver.find_element_by_name(name) def findCalssName(driver,className): return driver.find_element_by_class_name(className) def findXpath(driver,xpath): return driver.find_element_by_xpath(xpath) def findCssSelector(driver,cssSelector): return driver.find_element_by_css_selector(cssSelector) def findTagsName(driver,tagName,index): return driver.find_elements_by_tag_name(tagName)[index]
多个元素定位的方式来进行,调整后的代码如下:
from selenium import webdriver import time as t def findID(driver,ID): return driver.find_element_by_id(ID) def findName(driver,name): return driver.find_element_by_name(name) def findCalssName(driver,className): return driver.find_element_by_class_name(className) def findXpath(driver,xpath): return driver.find_element_by_xpath(xpath) def findCssSelector(driver,cssSelector): return driver.find_element_by_css_selector(cssSelector) def findTagsName(driver,tagName,index): return driver.find_elements_by_tag_name(tagName)[index]
if __name__ == '__main__': driver=webdriver.Chrome() driver.get('http://www.baidu.com') findTagsName(driver=driver,tagName='input',index=7).send_keys('接口测试') t.sleep(3) driver.quit()
执行无任何的问题,但是有警告,具体警告信息为:
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py:606: UserWarning: find_elements_by_* commands are deprecated. Please use find_elements() instead warnings.warn("find_elements_by_* commands are deprecated. Please use find_elements() instead")
五、顶级思维
在上面有警告的信息中,我们可以具体到webdriver.py模块的606行看看警告信息,这部分的源码为:
def find_elements_by_tag_name(self, name): """ Finds elements by tag name.
:Args: - name - name of html tag (eg: h1, a, span)
:Returns: - list of WebElement - a list with elements if any was found. An empty list if not :Usage: :: elements = driver.find_elements_by_tag_name('h1') """ warnings.warn("find_elements_by_* commands are deprecated. Please use find_elements() instead") return self.find_elements(by=By.TAG_NAME, value=name)
很明显,按照官方的意思是,后面这种方式逐步的会被替代以及放弃,警告不是错误,但是让人不舒服,那么解决的思路是什么了?还是看官方的警告代码来分析,根据警告官方更加推荐我们使用(by=By.TAG_NAME, value=name)这种方式来解决,不管元素有多少个方法,我们只能分为两个,那就是单个元素定位和多个元素定位的方法,那么针对上面的封装进行改造,改造成(by=By.TAG_NAME, value=name)的模式,调整后的代码为:
from selenium import webdriver from selenium.webdriver.common.by import By import time as t def findID(driver,ID): return driver.find_element(By.ID,ID) def findName(driver,name): return driver.find_element(By.NAME,name) def findCalssName(driver,className): return driver.find_element(By.CLASS_NAME,className) def findXpath(driver,xpath): return driver.find_element(By.XPATH,xpath) def findCssSelector(driver,cssSelector): return driver.find_element(By.CSS_SELECTOR,cssSelector) def findTagsName(driver,tagName,index): return driver.find_elements(By.TAG_NAME,tagName)[index] if __name__ == '__main__': driver=webdriver.Chrome() driver.get('http://www.baidu.com') findTagsName(driver=driver,tagName='input',index=7).send_keys('接口测试') t.sleep(3) driver.quit()
再次修改后
from selenium import webdriver from selenium.webdriver.common.by import By import time as t def findElement(driver,*args): return driver.find_element(*args) def findElements(driver,*args): return driver.find_elements(*args) if __name__ == '__main__': driver=webdriver.Chrome() driver.get('http://www.baidu.com') findElements( driver, *(By.TAG_NAME,'input'))[7].send_keys('接口测试') # findElement(driver,*(By.ID,'kw')).send_keys('接口测试') t.sleep(3) driver.quit()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具