
前提摘要:
该自动化测试框架主要是由robotframework + python 构成;上层由RF构建自动化case,底层由python编写具体功能的函数;最后由这些函数(RF中叫关键字)构建成具体的自动化测试用例。
该框架可用来做web ui自动化测试,接口自动化测试,App自动化测试都可,主要看你底层如何编码,如何实现了!
?
框架优点:?
目前测试圈主要流行的测试框架有unittest,pytest,robotframework等等,个人觉得三者各有优劣,不好评价谁好谁坏;但是我个人觉得目前python + robotframework的方式是最优的方案,但是前提要具备python编码能力。
优点一:单纯的robotframework测试框架,灵活性不够,稍显死板,用seleniumLibrary构建自动化用例执行时稳定性不好。但是python + RF的模式能够让测试更加灵活,在底层实现任意你想要的功能,在上层RF中用函数构建用例也更加灵活且易读。
优点二:RF仅用来构建测试用例,测试功能由底层库实现;首先RF类似于Excel,条目清晰,可读性佳,且上手容易,对于手动测试的同学也可快速上手编写测试用例。
优点三:RF中已经集成了很多优秀的功能,比如失败重跑,给测试用例打标签,可以利用标签来决定执行与跳过。
优点四:RF中测试用例执行完成后可生成详细的测试log和清晰的测试报告(不像unittest 和pytest还要用写脚本生成)
优点五: ? 该框架中,所有的模块,包,工具均安装在独立的虚拟环境中,如此可保持环境的稳定性。做过自动化的同学都应该知道环境对于自动化来说是多么多么多么重要。
优点六:Robotframework中有个template(模板)的功能非常好用,和DDT的测试模式很像,只需写一套模板,case里导入模板后只需要填写不同的测试数据即可,这是我最爱的功能!
?
框架介绍:
由于我们目前用的这套测试框架内容比较多,且由于项目保密需要我将很多项目内容做了删除,但是框架是完整的。为了更清晰的展示框架结构,我画了一张思维导图, 这张图花了我一两个小时,如果想了解该框架,请细读:

?这个框架中主要有2部分比较重要:Evironment 和 Library,Environment中存放case相关的, Library中则存放底层的库。因为项目原因我删除了很多项目相关内容,目前框架中只剩下两个Library:ModbusRobot(工业用的Modbus相关的操作) 和DeviceRobot(具体项目的操作)
目前DeviceRobot中剩下的common的东西我简单介绍一下:
enum 下面几个py文件存放的是一些枚举类,比如装置型号,modbus寄存器等等等;keywords下面存放的就是项目的主要代码,根据功能块来划分,但这里的主要业务相关的代码不便展示。、
common文件中是一些通用的函数,可供项目开发复用的,包含获取日志文件夹,格式化文件,重命名文件,压缩文件,文件内容比较,封装后的访问接口的函数等等等。pages中存放的是go to各个网页的函数。sleniumext是基于seleniumLibrary 封装的扩展函数,比如等待网页刷新,等到网页包含某字符,get cookies 等等,具体可Github自行查看。这里不多赘述。

?
如何开始使用?
step 1:?
使用框架前需要先构筑环境,运行Setup/Setup-Dev-Environment.bat,此命令会自动下载第三方的模块和库并且安装至.venv的虚拟环境中;会将RF的全局变量写入RIDE中,这样工具打开即用。为什么用虚拟环境以及用虚拟环境的好处此处不多做赘述,大家自行百度python虚拟环境相关知识。

step 2:?
使用pycharm(这里我使用的代码编辑工具是pycharm,用vs code也可以)打开项目工程,如图:

接下来就是在Library中编写函数(关键字)了, 这里我简单举个获取网页配置的例子:
首先,需要在keywords文件夹下新建一个configuratipon.py文件专门用来写网页配置相关函数;我们用attr模块来构建一个默认配置的类:
import attr
@attr.s
class CNFSyslog(object):
active = attr.ib(default=False)
primaryIpAddress = attr.ib(default='0.0.0.0')
primaryPort = attr.ib(default=514)
secondaryIpAddress = attr.ib(default='0.0.0.0')
secondaryPort = attr.ib(default=514)
关于attr模块其实相当于namedtuple增强版,具体解释我找了篇文章给大家: Python attr模块代码示例 - 纯净天空
?
然后,先新建一个名为_ConfigurationKeywords的类,如图:
class _ConfigurationKeywords(_Context):
def __init__(self, *args):
super().__init__(*args)
self._common = _CommonKeywords(*args)
self._device = _DeviceKeywords(*args)
self._logon = _LogonKeywords(*args)
self._seleniumext = _SeleniumExtKeywords(*args)
?再然后,开始开始再类中编写获取syslog的配置的函数:
def get_syslog_configuration(self):
conf = CNFSyslog() # 实例化默认配置的类
self._sel.go_to(self._device.get_device_address('/ConfSysLog.html')) # 去到配置页
self._sel.wait_until_page_contains_element('id:footer') # 等待页面加载完成
conf.active = int(self._sel.get_value('css:input[name="SysLogEnable_0"]:checked')) == 2 # 通过css定位获取激活状态
if conf.active:
conf.primaryIpAddress = self._sel.get_value('name:PriServerIpAddr') # 获取当前网页配置的ip地址
conf.primaryPort = self._sel.get_value('name:PriServerPort') # 获取当前网页配置的port
conf.secondaryIpAddress = self._sel.get_value('name:SecServerIpAddr') # 获取当前网页配置的second ip地址
conf.secondaryPort = self._sel.get_value('name:SecServerPort') # 获取当前网页配置的second port
return conf # 返回获取的配置
再然后,编写一个设置syslog网页的函数:
def set_syslog_configuration(self, active=None, primaryIpAddress=None, primaryPort=None, secondaryIpAddress=None, secondaryPort=None):
conf = self.get_syslog_configuration()
# 入参处理
active = robottypes.is_truthy(active) if active is not None else conf.active
primaryIpAddress = primaryIpAddress if primaryIpAddress is not None else conf.primaryIpAddress
primaryPort = int(primaryPort) if primaryPort is not None else conf.primaryPort
secondaryIpAddress = secondaryIpAddress if secondaryIpAddress is not None else conf.secondaryIpAddress
secondaryPort = int(secondaryPort) if secondaryPort is not None else conf.secondaryPort
# 去到设置页
self._sel.go_to(self._device.get_device_address('/ConfSysLog.html'))
self._sel.wait_until_page_contains_element('id:footer')
if active != conf.active:
with self._seleniumext.wait_until_page_contains_element_after_pageload('id:footer'):
self._sel.select_radio_button('SysLogEnable_0', str(int(active) + 1))
if active:
# 开始进行设置
if primaryIpAddress != conf.primaryIpAddress:
self._sel.input_text('name:PriServerIpAddr', primaryIpAddress)
if primaryPort != conf.primaryPort:
self._sel.input_text('name:PriServerPort', str(primaryPort))
if secondaryIpAddress != conf.secondaryIpAddress:
self._sel.input_text('name:SecServerIpAddr', secondaryIpAddress)
if secondaryPort != conf.secondaryPort:
self._sel.input_text('name:SecServerPort', str(secondaryPort))
with self._seleniumext.wait_until_page_contains_element_after_pageload('id:footer'):
self._sel.find_element('css:input.button[type="submit"]').send_keys(Keys.ENTER)
最后, 需要在库的 Libraries\DeviceRobot\src\DeviceRobot\init 文件中导入一下新建的_ConfigurationKeywords的类,因为所有的函数都是在这里开放给robotframework使用的,不然RIDE中无法使用
step 3:
到这里,底层的两个关于配置的函数已经写好了,可以打开RIDE来使用这两个函数编写自动化case了。
首先,运行框架内Environment/StartRIDE.bat 脚本,此脚本是打开RIDE工具, 打开后新建一个testsuit, 再新建一个testcase,然后就可以用刚才的两个函数编写case了:

?运行的话点击顶部工具栏start按钮即可。
Step 4:
在RIDE中编写自动化case需要掌握robotframework的使用方法,以及自带的常用关键字。这方面可参考虫师的robotframework 自动化测试;不过我觉得这本书知识点老旧,覆盖面也不全(比如底层自定义关键字说的一笔带过,没啥深度)。所以最终还是推荐看官方文档。
?
源码分享:?
源码在托管在Github:https://github.com/xgh321324/TA-Environment
?
写在最后:
框架内容较多,因工作时间较忙,抽空会丰富下该篇博客的内容。
如果大家有疑问,欢迎加QQ:970185127 一起讨论,互相学习!
|