51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 1398|回复: 1
打印 上一主题 下一主题

Robot Framework 使用总结

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2018-2-27 15:03:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近项目上使用了RF快速实现了一些验收测试的自动化case,感觉不错,很好用,下面就记录一下使用RF实现自动化的过程。
什么是RF?
RF是一种测试框架,帮助测试人员在其框架下快速实现验收测试的自动化。提供很多的扩展库供你使用,在没有任何一种语言编程基础的情况下也能实现一些自动化测试用例。
说白了,任何一种框架的作用就是帮你完成一些基础的工作,使你更加关注于要测试的业务逻辑,而不是关心技术细节,这些技术细节包括用例如何运行、如何组织、日志怎么记录,怎么展现,如何与CI集成等等。
使用RF框架与Jenkins CI工具结合,可以很容易的实现测试的远程部署、运行与结果展现。比起重写造轮子,自己写一套系统,这种方式还是快得多,最适合刚刚起步的项目。
RF能做什么?
RF能做什么取决于使用什么样的扩展框架,RF提供的默认内置库与外部扩展库,当然也可以自己写扩展库来定制功能。基本提供的库已经可以满足一般的测试需求了,包括对手机端、网页端的自动化测试,还有API接口的测试。
编写RF文件
RF文件通常以robot为后缀名,并且提供了很多的编辑工具,方便的进行robot文件的编辑。我使用的是pycharm的RF插件进行编辑,因为需要使用python写大量的扩展库,所以在pycharm里面统一进行robot与py文件的编辑,还是很方便的。或者使用官方的RIDE也是很好的选择,纯图形化界面,方便团队没有开发经验的人参与其中。
RF文件的结构
先看一个RF文件示例:
如上所示,一个RF文件通常包括三个节点:
  • Settings节点:1. 设置此test suite的setup与tearndown操作 2. 此test suite 中每个test case的setup与tearndown操作 3. 指定测试模板test template 4. 指定此test suite引用的资源文件的位置 5. 使用Library关键字引用RF标准库,或者自定义库:
  • Test Cases节点: 1. 可以定义一个普通的测试用例 2. 也可以调用模板,并给模板传入它所需要的参数 3. 测试用例里面所调用的关键词可能来自下面三个地方: * 当前test suite文件的keywords节点中定义的keyword * Setttings节点指定的资源文件中所定义的keyword * 内建的BuiltIn库中定义的keyword
  • Keywords节点: 1. keyword可以理解为一个公用的方法,供test case使用 2. keyword可以传入参数,返回结果 3. RF也提供很多逻辑判断IF,循环FOR等关键词

Resource资源文件的结构
其实resource文件与普通robot文件没多大区别,只不过它是被导入的库文件,通常用来定义一些公用的变量和keywords:
编写自己的Library文件
RF运行使用很多语言编写自己的Library文件,这里选择python编写,首先看一下对已存在的库文件的扩展
对selenium2library库文件的扩展:
  1. # 导入Selenium2Library模块
  2. from Selenium2Library import Selenium2Library模块
  3. from selenium.common.exceptions import StaleElementReferenceException
  4. import time


  5. def _get_table_field_value(element, field):
  6.     return element.find_element_by_xpath("./td[@field='" + field + "']").text.strip()

  7. # 继承Selenium2Library
  8. class CustomSeleniumLibrary(Selenium2Library):
  9.     def get_table_row_count(self, table_locator):
  10.         attempts = 0
  11.         while True:
  12.             try:
  13.                 table = self._table_element_finder.find(self._current_browser(), table_locator)
  14.                 return len(table.find_elements_by_xpath("./tbody/tr"))
  15.             except StaleElementReferenceException:
  16.                 time.sleep(1)
  17.                 if attempts >= 1:
  18.                     raise AssertionError("Cell in table %s could not be found." % table_locator)
  19.                 else:
  20.                     pass
  21.             attempts += 1

  22.     def get_user_search_results(self, table_locator, row_index):
  23.         table = self._table_element_finder.find(self._current_browser(), table_locator)
  24.         ret = []
  25.         if table is not None:
  26.             rows = table.find_elements_by_xpath("./tbody/tr")
  27.             if len(rows) <= 0:
  28.                 return None
  29.             row_index = int(row_index)
  30.             if len(rows)-1 < row_index:
  31.                 raise AssertionError("The row index '%s' is large than row length '%s'." % (row_index, len(rows)))
  32.             for row in rows:
  33.                 dic = {
  34.                     'userId': _get_table_field_value(row, 'userId'),
  35.                     'nickName': _get_table_field_value(row, 'nickName'),
  36.                     'realName': _get_table_field_value(row, 'realName'),
  37.                     'mobile': _get_table_field_value(row, 'mobile'),
  38.                     'idNo': _get_table_field_value(row, 'idNo'),
  39.                     'userType': _get_table_field_value(row, 'userType'),
  40.                     'verifyUserStatus': _get_table_field_value(row, 'verifyUserStatus'),
  41.                     'operator': _get_table_field_value(row, 'operater'),
  42.                     'operateTime': _get_table_field_value(row, 'operateTime'),
  43.                 }
  44.                 ret.append(dic)
  45.             return ret[row_index]
  46.         else:
  47.             return None

  48.     ...
  49. 创建全新的库文件:

  50. # -*- coding: utf-8 -*-

  51. from libs.DB_utils.utils import *
  52. from libs.request_utils import utils
  53. from libs.request_utils import flow_task_manage
  54. from libs.global_enum import *
  55. from libs.model import user_search_result
  56. from robot.libraries.BuiltIn import BuiltIn
  57. import time


  58. class VerifyLibrary(object):

  59.     def __init__(self, base_URL, username, dubbo_web_base_URL=None):
  60.         self.base_URL = base_URL
  61.         self.username = username
  62.         self.request_utils = utils.RequestUtil(base_URL, username)
  63.         self.flow_task_request_utils = flow_task_manage.FlowTaskManage(base_URL, username)
  64.         self.built_in = BuiltIn()
  65.         if dubbo_web_base_URL is not None:
  66.             self.dubbo_web_request_utils = utils.RequestUtil(dubbo_web_base_URL)

  67.     def update_verify_user_role(self, email, dept_id, role_id, amount_limit=5000):
  68.         real_name = get_verify_user_name_by_email(email)
  69.         verify_user_id = get_verify_user_id_by_email(email)
  70.         self.request_utils.login()
  71.         response = self.request_utils.update_verify_user(real_name, verify_user_id, amount_limit, dept_id, role_id)
  72.         return response.json()
复制代码
注意VerifyLibrary的构造函数,需要最少传入两个参数,这是在robot文件引用此库文件的时候传入的:
RF框架与Jenkins CI集成
使用Jenkins来运行RF写的test case很简单,首先需要在Jenkins上安装RF扩展插件:

然后,使用pybot命令行去运行写好的RF测试用例:

最后执行完测试后,可以在jenkins上很好的解析出测试结果的走势与具体的每个build的测试结果:




分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-17 18:39 , Processed in 0.064664 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表