Python+selenium+unittest的GUI自动化框架实现
框架设计说明图:
框架实现前的准备工作:
1.Python版本为2.7.11的Windows下的安装。
2.命令行下的selenium最新版本(编者使用版本为2.53.0,可兼容最新火狐、IE、chrome等浏览器版本)pip安装。
3.版本为Version: Mars.1 Release (4.5.1)的eclipse安装(编者Python开发使用工具),jdk1.7。
4.eclipse下Python开发插件PyDev 4.5.1(高版本不一定兼容当前eclipse版本与Java版本,高版本安装成功后,eclipse中找不到对应PyDev插件)。
5.Python下的MySQL数据库(编者使用数据为MySQL)模块安装MySQL-python-1.2.4b4.win32-py2.7(注意模块版本与系统位数,要与安装Python相同)。
6.Python反编译模块uncompyle-master安装(或许会用到)。
7.Python可执行打包模块py2exe-0.6.9.win32-py2.7安装(或许会用到)。
框架实现的可行性:
1.扩展方便,类似于Python的模块化安装。
2.易于维护,针对selenium的最新版本升级(兼容浏览器的最新版本等)只需命令行下执行:pip install -U selenium即可实现。
3.实现语言简单易学,针对Python的学习只要是不过于追求高大上(重构、复杂多态等),基本很快时间内即可搞定。
4.各浏览器均可兼容使用(编者的其它文章中有介绍IE、chrome等浏览器的调用)。
框架实现思路说明:
开篇啰嗦:
思路说明前,啰嗦两句(毛病是改不掉了)。小编同事过很多大牛,写出的代码非常牛叉(功能、性能、可读性等),设计的项目框架各种优秀,但是至于很多项目开发人员,很难达到框架设计之初的实现思路,按照初始的框架设计做项目实现。归根结底是由于项目从事人员未能达到思想上的一致,即框架设计人员未能将框架设计思想很好的传达给项目从事人员,不能让项目人员统一实现思想,导致后面项目可能出现的无法进行以及实现过程中的各种困难(项目人员A认为按照框架能够实现沙发的制作、项目人员B却认为按照框架只能设计出板凳来,思想上的不统一)。更多的事框架的设计未能较好的被理解。不管做什么,编者始终认为思路是第一位的。
测试用例代码实现存放模块:
import unittest
from time import sleep
from common.driverElement import driverElement
class CrmLoginTest(unittest.TestCase):
def setUp(self):
self.driverElement=driverElement()
self.driver=self.driverElement.webdriverInit('http://crm.360.cn/login')
def tearDown(self):
self.driver.quit()
def testName(self):
self.driverElement.webdriverLogin(self.driver)
sleep(4)
代码很简单,定义了系统登录测试的一个实现类CrmLoginTest,该实现类继承了unittest模块的TestCase接口定义的多个方法:setUp、tearDown、testName。
unittest类似于Java的TestNg,都是用于各自语言单元测试用。只不过实现方式不同罢了。具体看测试实现类继承的方法,setUp用于测试用例执行前的准备工作,包括数据库的连接建立、用例需用数据的预制准备等。testName方法定了用例具体实现用到的一些操作,对页面用户名、密码输入,点击页面【登录】按钮等一系列的手工测试操作。tearDown方法,用于用例运行完成后的垃圾数据回收、数据库连接断开等用例结束操作。
测试实现类中setUp、tearDown、testName三方法的执行顺序不以出现的先后顺序做执行,不管三方法出现的顺序为何,均优先执行setUp,在执行testName、testName1.。。最后执行tearDown。
上面是介绍的测试用例实现思路,测试用例代码实现存放模块实现思路是,该模块下只允许存放测试用例方法(CRMResourcesTest)与测试用例数据文件(Login.json)以及目录(用于标示测试用例所属不同层级)。此处区分测试用例方法与测试用例数据文件是自动化实现思想中“数据与脚本分离的重要实现”。数据与脚本分离后便于自动化用例维护(只需维护json文件即可实现用例的维护,无需修改测试脚本)。随着自动化越做越多,你会发现数据与脚本分离是多么重要的一件事情。
公共逻辑代码封装存放模块:
上面代码中testName方法中只用到了self.driverElement.webdriverLogin方法,即实现了系统登录。实际的手工测试操作,登录页面的完成需要“输入用户名”、“输入密码”、“点击【登录】按钮”三步实现系统登录操作。此处只用到了“一步”即实现了系统登录,怎么看能,查看公共逻辑代码封装存放模块下的driverElement.py文件,可以看到webdriverLogin方法具体为:
def webdriverLogin(self,driver):
elementaction=ElementActionutil()
elementaction.textinput(driver, elementname='js_uname', method='Class', text=self.f.getGlobalFileattrs('Login.json', 'username'), timeout=2)#用户名输入
elementaction.textinput(driver, elementname='js_upwd', method='Class', text='123456')#密码输入
elementaction.singleclick(driver,elementname='btnsend',method='Id')#点击【登录】按钮
print 'System login successfully!'
通过上面代码可以看到,看到的“一步”,其实际为三个步骤的一个封装,此处针对上述三个步骤做封装,是因为此三个步骤很多用例中都会用到,封装之后,各个测试用例直接调用“一步”方法即可实现系统登录,无需每个用例中均写三个步骤,代码美观易读,且方便实现。这就是“公共逻辑代码封装存放模块”的存在意义,针对代码中重复用到的公共步骤封装存放。当然针对公共步骤的封装实现用到的测试数据,有公共数据文件存放,如:baseaction下的Login.json文件,存放的就是公共逻辑代码中用到的数据。
GUI页面动作代码存放模块:
具体看模块下elementActionUtil.py文件中singleclick方法:
def singleclick(self,webdriver,elementname='',method='Id',timeout=2):
'method value:Id,Name,Class,xpath;webdriver value Firefox,Ie'
element1=waitforElementPresentAction.waitforElementPresentAction(webdriver, elementname, method, timeout)
element1.click()
公共逻辑代码封装存放模块中 elementaction.singleclick步骤,其实现就是以上代码,实际手工测试中鼠标单击操作,在代码实现中并不是一个底层方法就可实现的,往往实现起来可能需要N多操作。对谁执行、执行什么等等。特别是涉及到网络较差的情况,手工测试知道等待多长时间即可执行单击操作,但是自动化代码却要想方设法完成手工操作的智能化,其实现可想而知。
此处“GUI页面动作代码存放模块”中,只需包含elementActionUtil.py单文件即可,文件中定义各种页面操作:鼠标单击动作、鼠标双击动作、文本输入动作、单选按钮选择动作、复选按钮选择动作、页面元素是否可见、元素控件是否存在等等。各种页面动作的集合,即实现了页面自动化所需的各种手工实现。
底层代码模块:
底层代码模块定义了 公共逻辑代码封装存放模块中 各个动作步骤用到的核心代码,包括动作执行时间、如何查找元素控件(类似于人眼识别)、针对何种控件执行识别等等,举例代码如下:
def waitforElementPresentAction(webdriver,elementname='',method='Id',timeout=2):
'method value:Id,Name,Class,xpath;webdriver value Firefox,Ie,takes a WebDriver instance and timeout in seconds'
element1=None
end_time = time.time() + timeout
while True:
try:
if method=='Id':
element1=webdriver.find_element_by_id(elementname)
elif method=='Name':
element1=webdriver.find_element_by_name(elementname)
elif method=='Class':
element1=webdriver.find_element_by_class_name(elementname)
elif method=='Xpath':
element1=webdriver.find_element_by_xpath(elementname)
if element1:
return element1
except Exception:
pass
if time.time()>end_time:
assert False,'NoSuchElementException '+elementname+' with the method '+method#此处为何如此实现,请读者朋友给个回复。
文件操作代码存放模块:
该模块存放了如何实现测试用例数据文件内容读取操作的各个方法,方法实现的同时,也定义了测试数据文件的储存格式,数据文件不同后缀形式的读取等等操作,均存放在“文件操作代码存放模块”中。
数据库代码存放模块:
该模块定义了针对数据库的各种操作实现:增、删、改、查,建表、调用存储过程等等的数据库操作。该模块存在意义就是,手工测试过程中,针对前台页面操作完成后,后台数据库入表的正确性验证操作的自动化代码实现,以及测试用例执行前的测试数据预制实现等等。
日志文件代码存放模块:
日志文件代码存放模块定义了日志文件生成如何实现,针对测试用例级实现,运行多个用例、套件级用例运行测试,如何分析用例运行情况,通过用例运行输出日志即可实现用例运行正确性的检查。此处代码编者暂未实现,后面时间允许会加以完成。
框架不足以及待优化:
1.单个测试方法如何实现多个测试用例,即如何定义数据文件层级结构等。
2.日志文件如何定义实现。
3.单个用例测试执行、多用例测试执行(套件测试执行)测试报告的输出等。
4.代码傻瓜式实现等。
。。。。。。。。
未完、已完、待续。。。。。或许
本文出自 “江河一滴水” 博客,请务必保留此出处http://yidishui.blog.51cto.com/6297932/1783234