python基于Selenium的web自动化框架
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
python基于Selenium的web⾃动化框架
1 什么是selenium
Selenium 是⼀个基于浏览器的⾃动化⼯具,它提供了⼀种跨平台、跨浏览器的端到端的web⾃动化解决⽅案。
Selenium主要包括三部分:Selenium IDE、Selenium WebDriver 和Selenium Grid:
Selenium IDE:Firefox的⼀个扩展,它可以进⾏录制回放,并可以把录制的操作以多种语⾔(例如java,python等)的形式导出成测试⽤例。
Selenium WebDriver:提供Web⾃动化所需的API,主要⽤作浏览器控制、页⾯元素选择和调试。
不同的浏览器需要不同的WebDriver。
Selenium Grid:提供了在不同机器的不同浏览器上运⾏selenium测试的能⼒
本⽂中主要使⽤python结合Selenium WebDriver库进⾏⾃动化测试框架的搭建。
2 ⾃动化测试框架
⼀个典型的⾃动化测试框架⼀般包括⽤例管理模块、⾃动化执⾏控制器、报表⽣成模块和⽇志模块等,这些模块之间不是相互孤⽴的,⽽是相辅相成的。
下⾯来介绍下每个模块的逻辑单元:
⽤例管理模块
⽤例管理模块包括⽤例的添加、修改、删除等操作单元,这些单元也会涉及到⽤例书写的模式,测试数据的管理、可复⽤库等
⾃动化执⾏控制器
控制器是⾃动化⽤例执⾏的组织模块,主要负责以什么⽅式去执⾏⽤例。
⽐较典型的控制器有⽤户图形界⾯(GUI)和“commandline+⽂件”两种。
报表⽣成模块
报表⽣成模块主要负责执⾏完⽤例以后⽣成报表,报表⼀般以HTML格式居多,信息主要包括⽤例的执⾏情况及相应的总结报告。
另外还可以添加发送邮件功能。
⽇志模块
⽇志模块主要⽤来记录⽤例的执⾏情况,以便于更⾼效的调查⽤例失败信息及追踪⽤例执⾏情况。
3 ⾃动化框架的设计与实现
3.1 需求分析
测试对象是⼀个典型的后台系统的Web展现平台,基于此平台设计的⾃动化框架要包含测试⽤例管理、测试执⾏控制、测试报表及测试⽇志的⽣成,整体测试框架要轻量易⽤。
3.2 概要设计
概要设计包括了四个⼤的模块:公共库模块(可复⽤函数、⽇志管理、报表管理以及发送邮件管理)、⽤例仓库(具体⽤例的管理)、页⾯管理(单独对Web 页⾯进⾏抽象,封装页⾯元素和操作⽅法)以及执⾏模块。
概要设计类图:
3.3 详细设计与实现
3.3.1 页⾯管理
测试Web对象是⼀个典型的单页⾯应⽤,因此采⽤页⾯模式(page pattern)来进⾏组织:
页⾯模式是页⾯与测试⽤例之间的桥梁,它将每个页⾯抽象成⼀个单独的页⾯类,为测试⽤例提供页⾯元素的定位和操作。
页⾯模式的类图如下:
BasePage作为基类只包含⼀个driver成员变量,它⽤来标记Selenium中的WebDriver,以便在BasePage的派⽣类中定位页⾯元素。
LoginPage和PageN等作为派⽣类,可以提供相应页⾯元素的定位和操作⽅法。
⽐如测试对象的登录页⾯:
从页⾯可以看出,需要操作的页⾯元素分别为:Username,Password,remember my username checkbox和Sign in按钮,它们对应的操作为输⼊⽤户名和密码,点选checkbox和点击Sign In按钮,具体代码级别的实现如下:
页⾯基类BasePage.py:
class BasePage(object):
"""description of class"""
#webdriver instance
def __init__(self, driver):
self.driver = driver
LoginPage页⾯继承⾃BasePage,并进⾏Login Page的元素定位及操作实现。
代码中定位了username和password,并且添加了设置⽤户名和密码的操作。
from BasePage import BasePage
from mon.by import By
from mon.keys import Keys
class LoginPage(BasePage):
"""description of class"""
#page element identifier
usename = (By.ID,'username')
password = (By.ID, 'password')
dialogTitle = (By.XPATH,"//h3[@class=\"modal-title ng-binding\"]")
cancelButton = (By.XPATH,'//button[@class=\"btn btn-warning ng-binding\"][@ng-click=\"cancel()\"]')
okButton = (By.XPATH,'//button[@class=\"btn btn-primary ng-binding\"][@ng-click=\"ok()\"]')
#Get username textbox and input username
def set_username(self,username):
name = self.driver.find_element(*ename)
name.send_keys(username)
#Get password textbox and input password, then hit return
def set_password(self, password):
pwd = self.driver.find_element(*LoginPage.password)
pwd.send_keys(password + Keys.RETURN)
#Get pop up dialog title
def get_DiaglogTitle(self):
digTitle = self.driver.find_element(*LoginPage.dialogTitle)
return digTitle.text
#Get "cancel" button and then click
def click_cancel(self):
cancelbtn = self.driver.find_element(*LoginPage.cancelButton)
cancelbtn.click()
#click Sign in
def click_SignIn(self):
okbtn = self.driver.find_element(*LoginPage.okButton)
okbtn.click()
采⽤页⾯模式来管理页⾯和测试⽤例有很多好处,主要体现在:
简单并且清晰
每个页⾯都有单独的类来封装页⾯元素和操作,让页⾯操作更加具体化,⽽不是相对独⽴的。
⽐如未使⽤页⾯模式,测试⽤例的输⼊⽤户名和密码的代码:
#enter username and password
driver.find_element_by_id("username").clear()
driver.find_element_by_id("username").send_keys("sbxadmin")
driver.find_element_by_id("password").clear()
driver.find_element_by_id("password").send_keys("password"+Keys.RETURN)
使⽤页⾯模式之后,输⼊⽤户名和密码的代码:
#Step2: Open Login page
login_page = BasePage.LoginPage(self.driver)
#Step3: Enter username
login_page.set_username("username")
#Step4: Enter password
login_page.set_password("password")
通过对⽐我们不难发现,未使⽤页⾯模式的代码组织⽐较混乱,步骤多,可读性⾮常差,不难想象,⼀个通篇都是find_element_by_id或者send_Keys的测试⽤例到底有多糟糕!⽽使⽤了页⾯模式之后,在哪个页⾯做什么操作都⾮常清晰,⾮常接近测试⽤例的步骤,易读性⾮常好。
可复⽤性好
由于页⾯操作都被封装在了页⾯类中,所以页⾯⽅法和容易调⽤,可复⽤性⾮常好。
⽽未使⽤页⾯模式的⽤例只能每次都实现⼀遍。
可维护性好
由于测试⽬标页⾯的多变性,页⾯元素的定位经常需要改变,利⽤了页⾯模式后,只需要修改⼀遍其页⾯类中的定位就可以对所⽤⽤到该元素的测试⽤例⽣效;⽽在未使⽤该模式的情况下,必须修改每⼀个⽤到该元素的测试⽤例,⾮常容易遗漏,⼯作量也⾮常⼤。
综合以上页⾯模式的各种优点,我们在以后的web⾃动化中可以多使⽤该模式来组织页⾯。
3.3.2 公共库模块
公共库模块是为创建测试⽤例服务的,它主要包括常量、公共函数、⽇志管理、报表管理以及发送邮件管理等。
公共库模块涉及到的功能⼀般多⽽杂,在设计的时候只要遵循⾼内聚低耦合就可以了。
⽐如常量、变量和⼀些公共函数可以放在同⼀个⽂件中Common.py:
from datetime import datetime
def driverPath():
return r'C:\Users ua\Downloads\chromedriver_win32\chromedriver.exe'
def baseUrl():
return "https://xxx.xxx.xxx.xxx:9000"
#change time to str
def getCurrentTime():
format = "%a %b %d %H:%M:%S %Y"
return datetime.now().strftime(format)
# Get time diff
def timeDiff(starttime,endtime):
format = "%a %b %d %H:%M:%S %Y"
return datetime.strptime(endtime,format) - datetime.strptime(starttime,format)
测试⽤例信息类⽤来标识测试⽤例,并且包括执⾏⽤例执⾏结果信息,主要包括以下字段:
class TestCaseInfo(object):
"""description of class"""
def __init__(self, id="",name="",owner="",result="Failed",starttime="",endtime="",secondsDuration="",errorinfo=""):
self.id = id
= name
self.owner = owner
self.result = result
self.starttime = starttime
self.endtime = endtime
self.secondsDuration = secondsDuration
self.errorinfo = errorinfo
测试⽤例信息需要在每个测试⽤例中实例化,以便对测试⽤例进⾏标记,并最终体现在测试报告中。
⽇志主要⽤来记录测试⽤例执⾏步骤及产⽣的错误信息,不同的信息有不同的⽇志级别,⽐如Information,Warning,Critical和Debug。
由于每个测试⽤例产⽣的⽇志条⽬⽐较少,所以在测试框架中只利⽤了最⾼级别的⽇志打印,即Debug级别,该级别也会将其他所有的⽇志级别的信息同样打印出来。
在具体的实现中引⽤了Python标准库中的logging类库,以便更⽅便的控制⽇志输出:
import logging
import ResultFolder
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def CreateLoggerFile(filename):
try:
fulllogname = ResultFolder.GetRunDirectory()+"\\"+filename+".log"
fh = logging.FileHandler(fulllogname)
fh.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s [line:%(lineno)d] %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
except Exception as err:
logger.debug("Error when creating log file, error message: {}".format(str(err)))
def Log(message):
logger.debug(message)
报表管理及发送邮件模块实现了报表(html格式)的⽣成及⾃动发送邮件的功能。
报表和邮件依附于当前测试的执⾏,每次执⾏都会独⽴的触发报表⽣成和邮件发送。
该模块主要运⽤了Python中的lxml、smtplib和email库。
3.3.3 ⽤例仓库
⽤例仓库主要⽤来组织⾃动化测试⽤例。
每条测试⽤例都被抽象成⼀个独⽴的类,并且均继承⾃unittest.TestCase类。
Python中的unittest库提供了丰富的测试框架⽀持,包括测试⽤例的setUp和tearDown⽅法,在实现⽤例的过程中可以重写。
依托页⾯管理和公共库模块实现的页⾯⽅法和公共函数,每⼀个测试⽤例脚本的书写都会⾮常清晰简洁,⼀个简单的Floor Manager Lite的登录⽤例如下:
class Test_TC_Login(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome(cc.driverPath())
self.base_url = cc.baseUrl()
self.testCaseInfo = TestCaseInfo(id=1,name="Test case name",owner='xua')
self.testResult = TestReport()
LogUtility.CreateLoggerFile("Test_TC_Login")
def test_A(self):
try:
self.testCaseInfo.starttime = cc.getCurrentTime()
#Step1: open base site
LogUtility.Log("Open Base site"+self.base_url)
self.driver.get(self.base_url)
#Step2: Open Login page
login_page = LoginPage(self.driver)
#Step3: Enter username & password
LogUtility.Log("Login web using username")
login_page.set_username("username")
login_page.set_password("password")
time.sleep(2)
#Checkpoint1: Check popup dialog title
LogUtility.Log("Check whether sign in dialog exists or not")
self.assertEqual(login_page.get_DiaglogTitle(),"Sign in")
#time.sleep(3)
#Step4: Cancel dialog
login_page.click_cancel()
self.testCaseInfo.result = "Pass"
except Exception as err:
self.testCaseInfo.errorinfo = str(err)
LogUtility.Log(("Got error: "+str(err)))
finally:
self.testCaseInfo.endtime = cc.getCurrentTime()
self.testCaseInfo.secondsDuration = cc.timeDiff(self.testCaseInfo.starttime,self.testCaseInfo.endtime)
def tearDown(self):
self.driver.close()
self.testResult.WriteHTML(self.testCaseInfo)
if __name__ == '__main__':
unittest.main()
从这个测试⽤例中,我们可以看到
1.Setup中定义了执⾏测试⽤例前的⼀些实例化⼯作
2.tearDown对执⾏完测试做了清理和写⽇志⽂件⼯作
3.测试步骤、测试数据和测试检查点⾮常清晰,易修改(⽐如⽤户名密码)
4.⽇志级别仅有Debug,所以写⽇志仅需⽤同⼀Log⽅法
3.3.4 ⽤例执⾏模块(控制器)
执⾏模块主要⽤来控制测试⽤例脚本的批量执⾏,形成⼀个测试集。
⽤例的执⾏引⽤了Python标准库中的subprocess来执⾏nosetests的shell命令,从⽽执⾏给定测试⽤例集中的⽤例。
测试⽤例集是⼀个简单的纯⽂本⽂件,实现过程中利⽤了.txt⽂件testcases.txt:
Test_Login_pass.py
Test_Login_Fail.py
#Test_MainPage_CheckSecurityTableInfo.py
Test_MainPage_EditSecurityInfo.py
⽤例前没有“#“标记的测试⽤例脚本会被执⾏,⽽有”#“标记的则会被忽略,这样可以很⽅便的控制测试集的执⾏,当然也可以创建不同的⽂件来执⾏不同的测试集。
具体的调⽤代码如下:
def LoadAndRunTestCases(self):
try:
f = open(self.testcaselistfile)
testfiles = [test for test in f.readlines() if not test.startswith("#")]
f.close()
for item in testfiles:
subprocess.call("nosetests "+str(item).replace("\\n",""),shell = True)
except Exception as err:
LogUtility.logger.debug("Failed running test cases, error message: {}".format(str(err)))
finally:
EmailUtils.send_report()
3.4 执⾏结果
测试⽤例执⾏完毕后主要有两种输出:⽇志和测试报告。
测试报告会html附件的形式通过邮件发出,例如:
4 需要改进的模块
对于现有实现的测试框架,已经可以满⾜web对象的⾃动化需求,但还是有些可以改进提⾼的地⽅,⽐如:
针对部分测试⽤例是否可以尝试数据驱动添加屏幕截图功能封装selenium中By库中的函数,以便更⾼效的定位页⾯元素等结合业界优秀的⾃动化框架和实践持续改进
5 总结
基于selenium实现的web⾃动化框架不仅轻量级⽽且灵活,可以快速的开发⾃动化测试⽤例。
结合本篇中的框架设计以及⼀些好的实践,希望对⼤家以后的web⾃动化框架的设计和实现有所帮助。
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。