干货特供Selenium Webdriver实现发送短信自动化测试
Posted 智能化IT系统
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货特供Selenium Webdriver实现发送短信自动化测试相关的知识,希望对你有一定的参考价值。
一. 案例介绍
某系统后台,通过登录界面登录后,通过配置的短信模板,实现短信的发送。
登录界面如下图所示:
发送界面如下图所示:
本本案例通过网页自动化测试该系统功能的完善,采用Selenium Webdriver技术模拟用户操作。
模拟用户的动作:
填写用户名、密码,登录后台——>选择短信类型——>选择应用名称——>填写短信内容——>填写手机号码——>选择发送时间——>点击发送按钮
需要定位的页面元素:
登录页面:【用户名】输入框、【密码】输入框、【登录】按钮
发送短信页面:【选择短信类型】下拉框、【选择应用名称】下拉框、【短信内容】输入框、【手机号码】输入框、【发送时间】、【发送】按钮
二. selenium Webdriver技术介绍
1. 简介
selenium Webdriver是一套针对不同浏览器而开发的web应用自动化测试代码库。使用这套库可以进行页面的交互操作,并且可以重复地在不同浏览器上进行各种测试操作。
以python为例,在cmd输入python-m pip install selenium --upgrade pip进行安装。
2. 特点
开源免费
支持多种语言:Java、Python、Ruby、C#、javascript、C++等。
直接让测试工具调用浏览器和操作系统本身提供的内置方法,以此绕过JavaScript环境的沙盒限制。
支持多种浏览器。包括:Chrome、ie6-11、Firefox大部分版本、Mac操作系统的Safari默认版本、Opera、htmlUnit、android手机操作系统的默认浏览器、ios手机操作系统的默认浏览器。
3. 实现原理
如图,测试脚本作为客户端,在运行脚本的时候,
调用浏览器各自的webdriver(如Firefox的geckodriver)并创建session
webdriver启动浏览器,并绑定某端口成为Webdriver的Remote Server(作为服务端)
测试脚本发送基于selenium自己设计的The WebDriverWire Protocol协议的命令请求到Remote Server(这套协议几乎可以操作浏览器做任何事情,如打开、关闭、最大化、最小化、元素定位、元素点击、上传文件等。)
Remote Server将Web Service的命令转化成浏览器native的调用,在浏览器中找到元素的坐标位置,并在这个坐标点触发一个鼠标或键盘操作,从而操作浏览器。
4. 基本的元素定位方式
根据上述的实现原理,可知用selenium对浏览器进行页面操作的关键就是定位出页面上相应的元素,然后发送基于selenium自己设计的The WebDriver Wire Protocol协议的命令请求。
浏览器中,按F12或者各个浏览器提供的开发者工具,可查看页面元素。
Selenium提供了八种定位方式:
--id定位
§用法:find_element_by_id(“id对应的值”)
--name定位
§用法:find_element_by_name(“name对应的值”)
--class定位
§用法:find_element_by_class_name(“class对应的值”)
--tag定位
§用法:find_element_by_tag_name(“tag对应的值”)
--link定位(用于定位文本链接)
§用法:find_element_by_link_text(“链接的文本内容”)
--partial link定位(link定位的补充,可取链接部分文本内容进行定位)
§用法:find_element_by_partial_link_text(“链接的部分文本内容”)
--XPath定位
§用法:find_element_by_xpath(“xpath的值,可选中元素后,鼠标右键复制xpath”)
--CSS定位
§用法:find_element_by_css_selector(“CSS路径,同样可选中元素后,鼠标右键复制CSS路径”)
还可以用By定位元素(其实就是8种定位方法的另一种较灵活的写法):
--统一调用find_element()方法,通过By来声明定位方法(前面提到的8中定位方法),并传入对应定位方法的定位参数。
§用法:find_element(By.定位方法,“定位参数”)
e.g. find_element(By.ID,“txtAcc”)
三. 代码实现
这里我们采用Page Object设计模式来实现。(各页面的元素及相关操作各自封装在一个类,并与业务流程测试代码分离。)
如图所示:
BasePage.py模块中的BasePage作为基础类,封装了元素的基本操作(定位元素、点击、输入等),用于页面对象的继承。
Merchant_Login_Or_Out.py 、SendMessage.py模块分别封装了登录页面、发送短信页面的各个元素的定位器及相关操作。
test.py为主逻辑代码,模拟用户测试操作
关于检测的代码,本案例是在数据库进行验收条件的检测,本文中忽略这一部门的讲解。
1. BasePage.py
代码:
#! /usr/bin/env python # 告诉操作系统执行这个脚本的时候,调用/usr/bin下的python解释器
# coding=UTF-8 # 使用utf-8编码
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait# 基本类
class BasePage(object):
def __init__(self, driver, base_url='http://xxx.xxx.com/admin/login1'):
self.driver = driver
self.base_url = base_url
# 查找元素(此处定义的参数为可变参数,注意若传tuple或list时,参数前要加*拆包,# 即将tuple或list中的所有元素作为可变参数传入)
def find_element(self, *loc):
try:
# 设置等待,总等待时长8s,每隔1s轮询,直到定位到元素,并返回元素。
returnWebDriverWait(self.driver,8,1).until(lambda driver:driver.find_element(*loc))
except Exception as findEleErr:
print u"未能定位出元素:%s"%findEleErr
# send_keys操作
def input_text(self, loc, text):
self.find_element(*loc).send_keys(text)
# 定位到frame,并进行切换
def switch_to_frames(self, loc):
frame = self.find_element(*loc)
self.driver.switch_to.frame(frame)
# 定位到下拉框,并选择
def select_value(self, loc, value):
sel = self.find_element(*loc)
Select(sel).select_by_value(value)
# 定位并点击按钮
def click(self, loc):
self.find_element(*loc).click()
# 清除输入框内容
def clear_input(self, loc):
contents = self.find_element(*loc)
contents.clear()
代码简介:
第3行:导入webdriver提供的Select类,用于对下拉框的操作
第4行:导入webdriver提供的WebDriverWait类,用于设置等待元素
__init__ 方法:初始化动作,创建类的实例的时候,给实例的属性driver、url 自动赋值。
find_element方法:根据传入的定位参数,定位出页面相应的元素,并返回元素对象。
input_text 方法:根据传入的定位参数,定位出相应的输入框元素,并填写传入的文本内容
switch_to_frames方法:根据传入的定位参数,定位出相应的frame元素,并切换到该frame中
select_value方法:根据传入的定位参数,定位出相应的下拉框元素,并根据传入的value,选择对应的内容。
click方法:根据传入的定位参数,定位出相应的元素,并触发鼠标点击事件。
clear_input方法:根据传入的定位参数,定位出相应的输入框元素,并清除已填写的内容。
2. Merchant_Login_Or_Out.py
代码:
#! /usr/bin/env python
# coding=UTF-8
from selenium.webdriver.common.by import By
from selenium_text.BasePage import *
# 商户登录操作
class LoginPage(BasePage):
username = (By.ID, u'txtAcc')
password = (By.ID, u'txtPwd')
login_btn = (By.ID, u'submitButton')
def __init__(self,driver,base_url='http://xxx.xxx.com/admin/login'):
BasePage.__init__(self,driver,base_url)
def Login_Page(self):
print u'开始登录%s页面'%self.base_url
self.driver.get(self.base_url)
def set_username(self, username): # 输入用户名
name = self.input_text(self.username, username)
def set_password(self, password): # 输入密码
pwd = self.input_text(self.password, password)
def click_login(self): # 点击登录
loginbtn = self.click(self.login_btn)class Login():
def MerchantLogin(self,driver,name,password,url):
LoginPages = LoginPage(driver,url)
# 打开登录页面
LoginPages.Login_Page()
# 输入用户名
LoginPages.set_username(name)
# 输入密码
LoginPages.set_password(password)
# 点击登录
LoginPages.click_login()
time.sleep(1)
print u"登录成功"
代码简介
第3行:导入webdriver提供的By类。本文均统一调用find_element()方法,并传入By定位器,进行元素定位。
第4行:导入自定义的BasePage.py模块。登录操作LoginPage类继承BasePage类。
LoginPage类中:第9~11行,分别存放了用户名、密码、登录按钮的定位器。(若页面元素改动,可在这调整定位器。其实还应该入验证码,但在测试环境中对特定用户屏蔽了验证码操作,故不用考虑验证码的输入。)
Login_Page方法:根据传入的base_url,请求并打开相应页面。
set_username方法:根据传入的用户名定位器和账号,定位用户名输入框并填写。
set_password方法:根据传入的密码定位器和密码,定位密码输入框并填写。
click_login方法:根据传入的登录按钮定位器,触发点击操作。
Login类中的MerchantLogin方法:创建LoginPage类的实例,并调用LoginPage类的方法,进行填写用户名、密码、点击登录操作。
3. SendMessage.py
代码
#! /usr/bin/env python
# coding=UTF-8
from selenium.webdriver.common.by import By
from selenium_text.BasePage import *# 发送短信页面
# 存放定位器及封装发送短信页面所有操作动作
class SendMessages(BasePage):
#-------------------------定位器----------------------------------------------------
# 左侧栏的“发送短信”按钮
sendMessageEle = (By.XPATH, u'//*[@id="_MP8"]')
# “发送短信”页面的iframe
frameEle = (By.XPATH, u'//*[@id="rightMain"]')
# 短信类型下拉框
messageTypeSEle = (By.CSS_SELECTOR, u'html body div.pad-10 fieldset form#Form1 table. table-list01 tbody tr td select')# 应用下拉框
appSelEle = (By.XPATH, u'//*[@id="App"]')# 短信内容输入框
contentsEle = (By.XPATH, u'/html/body/div[2]/fieldset/form/table/tbody/tr[4]/td[2]/textarea[1]')# 电话号码输入框
PhoneNumEle =(By.XPATH, u'/html/body/div[2]/fieldset/form/table/tbody/tr[5]/td[2]/textarea')# 立即发送按钮
sendInTimeEle = (By.XPATH, u'/html/body/div[2]/fieldset/form/table/tbody/tr[6]/td[2]/input')# 定时发送按钮
sendOnTimeEle = (By.XPATH, u'/html/body/div[2]/fieldset/form/table/tbody/tr[6]/td[3]/input[1]')# 时间框
timeEle = (By.XPATH, u'//*[@id="BeginTime"]')
# 时间frame
timeFrameEle = (By.XPATH, u'/html/body/div[5]/iframe')
# 时间frame里的分钟项
minutesEle = (By.XPATH, u'/html/body/div[1]/div[4]/table/tbody/tr[1]/td[1]/input[3]')
# 加一键
PlusEle = (By.XPATH, u'//*[@id="dpTimeUp"]')
# 时间frame确认键
timeConfirmEle = (By.XPATH, u'//*[@id="dpOkInput"]')
# 发送按钮
sendEle = (By.XPATH, u'//*[@id="btn_Send"]')#初始化
def __init__(self,driver):
BasePage.__init__(self,driver)
# 切换到发送短信frame
def SwitchToFrame(self):
self.switch_to_frames(self.frameEle)
# 选择短信类型
def SelectMessageType(self, messageType):
self.select_value(self.messageTypeSEle, messageType)# 选择应用
def SelectApp(self, appSelVal):
self.select_value(self.appSelEle, appSelVal)# 定位到输入短信内容框,清除短信内容
def ClearSMSContents(self):
self.clear_input(self.contentsEle)# 定位到输入短信内容框,重新填写短信内容
def InputSMSContents(self, SMSContents):
self.input_text(self.contentsEle, SMSContents)
# 输入手机号
def InputPhoneNums(self, PhoneNums):
PhoneNums = PhoneNums.decode('utf-8')
PhoneNum = self.input_text(self.PhoneNumEle, PhoneNums)
# 点击立即发送按钮
def SendInTime(self):
self.click(self.sendInTimeEle)
# 点击定时发送按钮
def SendOnTime(self):
self.click(self.sendOnTimeEle)# 点击发送
def SendBtn(self):
self.click(self.sendEle)
# 点击时间插件
def TimeEleClick(self):
self.click(self.timeEle)
# 切换到时间frame
def SwitchToTimeFrame(self):
self.switch_to_frames(self.timeFrameEle)
# 点击时间插件的分钟,并增加分钟数
def MinsEleClick(self, plusMins):
self.click(self.minutesEle)
plusMins = int(plusMins) + 1
# 点击5次,增加5分钟
for i in range(1,plusMins,1):
self.click(self.PlusEle)
# 选择好时间后,点击确认
self.click(self.timeConfirmEle)# 执行发送短信步骤
class SendMessage(BasePage):
def __init__(self,driver):
BasePage.__init__(self,driver)
def SendMessage(self,driver,messageType,appSelVal,SMSContents,PhoneNums,SentIfOnTime,plusMins):SMd = SendMessages(driver)
# 切换到发送短信iframe
SMd.SwitchToFrame()
# 选择短信类型
SMd.SelectMessageType( messageType)
# 定位到应用下拉框 ,选择应用
SMd.SelectApp(appSelVal)
# 如果短信类型是短验,则需要清除短信内容,并重新填写短信
if messageType == '1':
# 定位到输入短信内容框,清除短信内容
SMd.ClearSMSContents()
# 定位到输入短信内容框,填写短信内容
SMd.InputSMSContents(SMSContents)
# 定位到手机号码输入框,填写手机号码
SMd.InputPhoneNums(PhoneNums)if SentIfOnTime == '0':
# 定位到立即发送按钮
SMd.SendInTime()
elif SentIfOnTime == '1':
# 定位到定时发送按钮
SMd.SendOnTime()
# 点击时间栏,弹出时间frame
SMd.TimeEleClick()
time.sleep(2)
# 因为之前切到了短信输入的iframe,所以要切回主文档
driver.switch_to.default_content()
# 定位到时间frame
SMd.SwitchToTimeFrame()
# 定位到分钟
SMd.MinsEleClick(plusMins)
# 返回主文档
driver.switch_to.default_content()
# 切回发送短信frame
SMd.SwitchToFrame()
# 点击发送按钮
SMd.SendBtn()
代码简介
第3~4行:导入要用到的库,by和BasePage
SendMessages类:第12~44行,存放发送短信页面各个元素的定位器。
SwitchToFrame方法:根据短信frame元素定位器,定位到相应的frame并切换。
SelectMessageType方法:根据短信类型下拉框元素定位器及短信类型,进行定位并选择。
SelectApp方法:根据应用下拉框元素定位器及应用id,进行定位并选择。
ClearSMSContents方法:根据短信内容输入框定位器,进行定位并清除内容。
InputSMSContents方法:根据短信内容输入框定位器及传入的短信内容,进行定位并填写。
InputPhoneNums方法:根据手机号码输入框定位器及传入的号码,进行定位并填写。
SendInTime方法:根据立即发送按钮定位器,进行定位并触发点击事件。
SendOnTime方法:根据定时发送按钮定位器,进行定位并触发点击事件。
SendBtn方法:根据发送按钮定位器,进行定位并触发点击事件。
TimeEleClick方法:根据时间插件定位器,进行定位并触发点击事件。
SwitchToTimeFrame方法:根据时间插件frame定位器,进行定位并切换。
MinsEleClick方法:根据时间插件里分钟项定位器、确认键定位器及传入的增加分钟数,进行定位、点击增加分钟数并点击确认。
SendMessage类的SendMessage方法:
——>先切换到发送短信的iframe中
——>定位到短信类型下拉框并选择
——>定位到应用下拉框并选择
——>根据传入的短信类型判断,如果是短验,要替换验证码内容,所以先清除短信内容,并重新填写短信。
——>定位到手机号码输入框,填写手机号码
——>根据传入的是否定时发送值判断,为0则定位到立即发送按钮并点击
——>若是否定时发送值为1,则定位到定时发送按钮并点击,
—>定位并点击时间插件,弹出时间插件的iframe
—>等待2s,因为可能操作太快,导致未正确点击
—>切换回主文档(因为之前切到了输入短信的iframe了)
—>定位并切换到时间插件iframe
—>定位到分钟项,并增加分钟数
—>切换回主文档
—>切换回发送短信iframe,因为发送按钮在发送短信iframe中
——>定位并点击发送按钮
4. test.py
代码
if RequestObj.ModelTitle.find('页面下单模块') != -1:
try:
# 启动虚拟显示服务(ps 能看到多了Xvfb、dbus-launch这两个进程)
# display = Display(visible=0, size=(1280, 1024))
# display.start()
ExplorerType = Dic_Param['ExplorerType']
# 创建webdriver类对象
if ExplorerType == 'Firefox':
driver = webdriver.Firefox()
elif ExplorerType == 'Chrome':
driver = webdriver.Chrome()# 登录后台
Login().MerchantLogin(driver,Dic_Param['UName'],Dic_Param['Password'],Dic_Param\ ['LoginUrl'])
if RequestObj.ModelTitle.find('XXX') != -1:
# 提交订单后,获取商户下单的任务编码。要转成字符串,否则后面替换参数会失败
LastTaskID = str(MethodList.GetTaskID(0,Dic_Param['UName'],1))
# 获取WelcomePage实例
WP = WelcomePage(driver)
# 进入相应的页面,并提交订单
if RequestObj.ModelTitle.find('发送短信') != -1:
# 到发送短信页面,发送短信
WP.ClickSendMessage()
Dic_Param['Content'] = Dic_Param['Content'].decode('utf-8')SendMessage(driver).SendMessage(driver,Dic_Param['ContentType'],Dic_Param\['AppId'],Dic_Param['Content'],Dic_Param['PhoneNum'],Dic_Param['SentIfOnT\ime'],Dic_Param['PlusMins'])elif RequestObj.ModelTitle.find('个性发信') != -1:
# 到个性发送页面,发送短信
WP.ClickUploadSendM()UploadSendMessage(driver).UploadSendMessage(driver,Dic_Param['AppId']\,Dic_Param['FilePath'],Dic_Param['SentIfOnTime'],Dic_Param['PlusMins'])# 如果是定时发送,则提交订单后,需要暂停相应的时间再进行校验结果。
if Dic_Param['SentIfOnTime'] == '1':
PlusSeconds = int(Dic_Param['PlusMins']) * 60 * 5
time.sleep(PlusSeconds)# 提交订单后,获取商户下单的任务编码。要转成字符串,否则后面替换参数会失败
CurTaskID = str(MethodList.GetTaskID(0,Dic_Param['UName'],1))
# 如果当前的任务编码小于等于下单前的任务编码,说明提交订单失败。
if LastTaskID < CurTaskID:
# 获取任务编码
Dic_Param['LastTaskID'] = str(MethodList.GetTaskID(0,\Dic_Param['UName'],1))
# 传入登录账号、预期生成订单数,获取鉴权自增id
OrdID = str(MethodList.GetMerchantOrderID(0,Dic_Param['UName'],\Dic_Param['PredictNums']))
Dic_Param["OrdID"] = CurTime + OrdID
print u'获取后台自增id=%s'%Dic_Param["OrdID"]if CaseDetail.find('回调失败') != -1:
Param_Str = 'MobilePhone='+Dic_Param['PhoneNum']+'&ReportState=\for i in range(1,20,1):
print u"第%s次刷新"%i
# 刷新页面(因为数据库任务列表的数据需要页面刷新了,才会更新数据)
driver.refresh()
点击并跳到任务列表页面
WP.ClickTaskList()
# 获取实例对象
TP = TaskListPage(driver)
# 获取任务列表的所有值
table_list = TP.Get_table_list()
# 任务列表中第一行的总数值
TotalNums = str(table_list[1][3])
# 任务列表中第一行的已提交数
SubmitedNums = str(table_list[1][4])
# 如果页面的已提交数不等于配置的PredictNums,则说明未生成订单,需要每 2s刷新页面,并重新获取数据
if TotalNums != Dic_Param['MobileNums'] or SubmitedNums != Dic_Param\['PredictNums']:
time.sleep(4)
else:
for i in range(1,4):
# 刷新页面(页面刷新了,数据库的任务列表才会更新数据)
driver.refresh()
# 点击并跳到任务列表页面( 有时候未及时更新需要再次刷新)
print u"再次刷新%s次"%i
WP.ClickTaskList()
# 退出循环
break
# 正常的操作结果,暂定为已完成
Request_Result = u'已完成'
else: # 如果当前任务编码小于等于下单前的任务编码,说明提交失败。
Dic_Param['LastTaskID'] = u'提交失败'
Request_Result = u'鉴权提交失败'
except Exception as pageErr:
print "pageErr:%s"%pageErr
Request_Result = u'页面操作有误,未生成订单'
finally:
# 记录所传的参数
Param_Str = json.dumps(Dic_Param,encoding='utf-8',ensure_ascii=False)
# 关闭浏览器
driver.quit()
# 终止display进程(如果用stop(),还会有dbus-launch这个进程(守护进程?))
# display.sendstop()
代码说明:
先根据模块名是否含页面下单,判断是否进入selenium相关程序。
第4~5行:注释代码,后续脚本部署到Linux上运行,需要调用虚拟显示服务。设置Display 环境变量后,启动Display。
第6~11行:获取用例模块中的ExplorerType参数的值,并对应创建webdriver类对象打开浏览器。(因为不同浏览器需要的webdriver都不一样。)
第15行:根据模块名是否包含该业务名,判断是否进行发送短信操作。
第17行:传入用户名,调用封装好的GetTaskID方法,获取任务编码。(因为提交订单后,会生成一个任务记录,并在【任务列表页面】中展示该记录。所以我们下单前后都获取一次任务编码,若下单后的任务编码没变,说明下单失败。)
第19~25行:创建欢迎页对象,根据模块名是否包含“发送短信”,点击欢迎页左侧栏的“发送短信”,进入发送短信页面。传入短信类型、短信内容等信息(这些都是读取模块配置的参数),调用SendMessage模块的SendMessage方法,进行发送短信操作。
第31~34行:根据模块参数“SendIfOnTime”判断,是否定时发送,如果是定时发送,则需要等待相应的时间再去数据库校验是否生成订单等信息。
第35~40行:提交订单后,再次获取当前任务编码,如果当前任务编码大于下单前的任务编码,说明提交订单成功,将当前任务编码赋值给模块参数“LastTaskID”作校验预期结果用。
第41~45行:获取后台订单号,并赋值给模块参数“OrdID”,作校验预期结果用。
第46~51行:配置的用例中,有订单回调失败的情况,所以如果用例详情包含了回调失败,则对对订单模拟回调失败。
第52~78行:提交完订单后,在校验预期结果之前,对任务列表页面中的任务记录进行初步的页面校验动作。任务主要记录提交的总号码数、已成功提交的号码数和提交失败(即未生成订单)的号码数。又因提交订单后,需要校验余额、进货价、风控等信息不一定会马上更新任务列表的结果。所以如果首次校验不通过,则这里是76s内, 每4s去刷新任务列表页面,并重新获取任务列表的数据,直到校验通过,退出循环。
最后,无论订单是否提交成功,都关闭浏览器(用例之间相互独立,每执行一条用例打开一次浏览器),然后进入校验预期结果的步骤。
四. Linux部署
桌面环境使用Selenium默认会打开浏览器界面,但是如果要部署到无桌面环境的服务器环境,使用普通方法没法运行Selenium。解决方法有:
使用HtmlUnitDriver或者PhantomJSDriver
使用XVFB(X virtual frame buffer)虚拟显示服务器,不需要借助任何显示设备,在内存中执行所有的图形操作。
本文采用安装Xvfb的方式。部署步骤如下:
1. 安装pyvirtualdisplay
pip install pyvirtualdisplay
2. 安装Xvfb(作为后端)
yum install xorg-x11-server-Xvfb
3. 安装Firefox
cd /usr/local
Wget https://ftp.mozilla.org/pub/firefox/releases/56.0.2/linux-x86_64/en-US/firefox-56.0.2.tar.bz2
tar xjvf firefox-56.0.2.tar.bz2
ln -s /usr/local/firefox/firefox /usr/bin/firefox
4. 下载geckodriver
wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz
5. 解压geckodriver-v0.19.1-linux64.tar.gz
tar xvzf geckodriver-*.tar.gz
6. 在环境变量目录/usr/bin/中添加geckodriver的硬链接
ln -s /usr/local/geckodriver /usr/bin/geckodriver
7. 测试脚本中添加代码
导入Display模块
from pyvirtualdisplay import Display
在创建webdriver实例前,设置Display环境变量。visible传0表示使用Xvfb作为后端,size传的参数就是设置浏览器页面大小。
Display = Display(visible=0, size=(1280, 1024))
启动虚拟显示服务
Display.start()
执行完用例后,关闭浏览器后,也需要终止Xvfb进程。
display.sendstop() # 先发送SIGTERM信号给Xvfb,让Xvfb自行了断,如果Xvfb进程还在,则继续发送SIGKILL强制结束Xvfb进程。
部署时可能遇到的坑:
1. 运行webdriver.Firefox()后等待很久报错并退出,显示selenium.common.exceptions.WebDriverException: Message: other os error:
可能是版本不兼容,可以把firefox,geckodriver以及selenium全部升级到新版本。
以上是关于干货特供Selenium Webdriver实现发送短信自动化测试的主要内容,如果未能解决你的问题,请参考以下文章
周一干货特供系统安全密码全面剖析三部曲之一:基本原理以及对称加密
“Selenium-server-standalone.jar”和“Selenium Client & WebDriver”有啥区别?
python+selenium+webdriver+BeautifulSoup实现自动登录