干货特供Selenium Webdriver实现发送短信自动化测试

Posted 智能化IT系统

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货特供Selenium Webdriver实现发送短信自动化测试相关的知识,希望对你有一定的参考价值。

一. 案例介绍

某系统后台,通过登录界面登录后,通过配置的短信模板,实现短信的发送。

登录界面如下图所示:

发送界面如下图所示:

【干货特供】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”有啥区别?

Selenium webdriver实现截图功能

python+selenium+webdriver+BeautifulSoup实现自动登录

java+selenium webdriver怎么实现数据参数化

Selenium高手必备:基于WebDriver的Web UI自动化