robotframework自动化测试框架实战教程:创建及使用测试库

目录

前言

创建测试库

一些重要的概念:

结语


前言

今天给大家讲一讲robotframework自动化测试框架创建及使用测试库的主要实践,通过这篇文章希望可以让大伙能完善和增强robotframework基本功能。

创建测试库

测试库的实现可以是Python模块, 也可以是Python类.

Python模块

 Python类

测试库通常在 Setting 表格中设置 Library 来导入, 库名称跟在 Library 后面. 不同于大部分的其它数据, 库名称既是大小写敏感的, 也是空白敏感的. 如果一个测试库是在某个文件里的, 则必须指明路径.

 测试结果

==============================================================================
Functest                                                                      
==============================================================================
测试库用例                                                            
我的方法

我的类
| PASS |
------------------------------------------------------------------------------
Functest                                                              | PASS |
1 test, 1 passed, 0 failed
==============================================================================

一些重要的概念:

  • 实现为类的测试库都可以接受参数. 这些参数在Setting表中指定, 跟在库名后面, 当Robot Framework创建测试库的实例时, 把这些参数传给构造函数.意思就是MyModule=MyModule(__init__方法的参数),之后使用MyModule.method。
    •   有个常用场景是通过数据库获取数据,就可以创建测试库完成。

      开始连接
      ==============================================================================
      Functest                                                                      
      ==============================================================================
      DBtest                                                                开始连接
      开始查询
      查询完成,数据为{'id': 1, 'username': 'admin', 'password': 'pbkdf2:sha256:260000$l0K5upqR$87143093593e3622bc700f3c57e91180ad05ccb51169b36617cfe3ac6207c9a2', 'nickname': '管理员', 'email': 'admin@163.com', 'isadmin': 0, 'group_id': 1, 'create_time': datetime.datetime(2022, 10, 15, 20, 19, 4), 'update_time': datetime.datetime(2022, 10, 15, 20, 19, 4), 'delete_time': None, 'update_user_id': None, 'create_user_id': None, 'update_user_name': None, 'create_user_name': None}
      | PASS |
      ------------------------------------------------------------------------------
      Functest                                                              | PASS |
      1 test, 1 passed, 0 failed
      ==============================================================================

  • 变量可以包含任何类型的对象作为值,用作参数的变量按原类型传递给关键字。默认情况下,关键字参数作为Unicode字符串传递给关键字。

    case1                                                                 
    <class 'str'>
    <class 'int'>
    <class 'str'>
    <class 'bool'>
    case1                                                                 | PASS |

    •   指定类型的最自然方式是使用Python函数注释,如果没有使用注释Robot Framework会尝试根据可能的参数默认值获取类型信息。转换失败时,关键字会获得原始值(Unicode字符串)。

    • 上面会转换为int和float类型,如果参数具有显式类型和默认值,转换失败会导致错误。

      case1                                                                 | FAIL |
      ValueError: Argument 'f' got value 'abc' that cannot be converted to float.
    • 指定显式参数类型的另一种方法是使用@keyword装饰器。它接受一个可选的types参数,该参数可以用于指定参数类型,既可以作为字典,也可以作为列表。

      @keyword(types={'count': int, 'bool': bool})
      @keyword(types=[int, bool])
    • 无论使用哪种方法,都不一定要为所有参数指定类型。当将类型指定为列表时,可以使用None来标记某个参数没有类型,并且末尾的参数可以完全省略。只为第二个参数指定类型案例

      @keyword(types={'bool': bool})
      @keyword(types=[None, bool])
    • 除了如前几节所述自动执行参数转换之外,Robot Framework还支持自定义参数转换。ROBOT_LIBRARY_CONVERTERS可以可以为测试库注册转换器,参数转换器是获取数据中使用的参数并在参数传递给关键字之前将其转换为所需格式的函数或其他可调用函数。

    • [info] year: 2022, month: 1, day: 25
      case1                                                                 | PASS |

      转换失败会抛出异常

      [FAIL] ValueError: Argument 'arg' got value 'invalid' that cannot be converted to date: not enough values to unpack (expected 3, got 1)
      case1                                                                 | FAIL |

      转换器也可以接受多个类型,将类型指定为Union。

      def parse_fi_date(value: Union[str, int]):

      通过将测试库实现为类,还可以与@library装饰器一起使用。以下案例说明

      case1
          FI     25.1.2022
          ISO 8601    2022-01-22
          ALL     2022-01-22
          ALL     25.1.2022
      [info] year: 2022, month: 1, day: 25
      [info] year: 2022, month: 1, day: 22
      [info] year: 2022, month: 1, day: 22
      [info] year: 2022, month: 1, day: 25

      上面案例显示如果参数是指定的开始类型(date),则不使用转换器。

  • 将库实现为模块时,模块命名空间中的所有函数都将成为关键字。对于导入的函数也是如此,这可能会引起令人讨厌的意外。例如,如果下面的模块用作库,它将包含关键字example keyword,但也包含关键字Current Thread。
    from threading import current_thread
    
    
    def example_keyword():
        print('Running in thread "%s".' % current_thread().name)

  避免导入的函数成为关键字的一个简单方法是只导入模块(例如导入线程),并通过模块使用函数(例如线程.current_thread())。或者,可以在导入时为函数提供一个以下划线开头的别名(例如,从线程导入current_thread作为_current_thread)。

    • 当库作为类实现时,可以通过将Robot_AUTO_keywords属性设置为false来告诉Robot Framework不要自动将方法公开为关键字

  

    •   或使用@library的类来告诉Robot Framework不要自动将方法公开为关键字

    •   可以使用@not_keyword修饰符显式标记为“not keywords”。

      case1                                                                 .f561aaf6ef0bf14d4208bb46a4ccb3ad
      case1                                                                 | PASS |
      ------------------------------------------------------------------------------
      case2                                                                 .698d51a19d8a121ce581499d7b701668
      case2                                                                 | PASS |
      ------------------------------------------------------------------------------
      case3                                                                 | FAIL |

  • 传递给库的参数, 包括库名本身, 都可以使用变量. 也就是说可以在某些时候, 例如命令行(--variable), 修改它们.
  • Robot Framework 为了保证测试用例之间的独立性, 默认情况下, 它为每个测试用例 创建新的测试库实例. 然而, 这种方式不总是我们想要的, 比如有时测试用例需要共享 某个状态的时候. 此外, 那些无状态的库显然也不需要每次都创建新实例.
    • TEST CASE 为每个测试用例创建新的实例. 如果有suite setup和suite teardown的话, 同样 也会新建. 这是默认行为.
    • TEST SUITE为每个测试集创建新的实例. 最底层的测试集, 也就是由测试用例文件组成的测试集, 拥有属于自己的测试库实例, 高层的测试集, 都有属于自己的测试库实例.
    • GLOBAL整个测试执行过程中只有一个实例被创建. 所有的测试集和测试用例共享这个实例. 通过模块创建的测试库都是全局的.
      from robot.api import logger
      
      class MyModule:
      
          ROBOT_LIBRARY_SCOPE = 'GLOBAL'
      
          def __init__(self):
              self._counter = 0
      
          def count(self):
              self._counter += 1
              logger.console(self._counter)
      
          def clear_counter(self):
              self._counter = 0

    可以通过@library设置

@library(scope=''GLOBAL'')
class MyModule:
  • 名称的比较是忽略大小写的, 并且其中的空格和下划线 也都忽略掉
  • 异常的回溯(traceback)信息在 日志级别 为 DEBUG 时也会被写入日志
  • 有时候, 出现了错误从而停止整个测试执行.最简单的方法是使用robot.api.FatalError

    ==============================================================================
    case1                                                                 | FAIL |
    FatalError: 系统终止运行
    ------------------------------------------------------------------------------
    case2                                                                 | FAIL |
    Test execution stopped due to a fatal error.
    ------------------------------------------------------------------------------
    Functest                                                              | FAIL |
    2 tests, 0 passed, 2 failed
    ==============================================================================

  • 希望即使出现故障,也可以继续执行测试。最简单的方法是使用robot.api.ContinuableFailure

    ==============================================================================
    case1                                                                 F此用例继续
    case1                                                                 | FAIL |
    系统继续运行
    ------------------------------------------------------------------------------
  • 希望即使出现故障,也可以跳过继续执行测试。最简单的方法是使用robot.api.SkipExecution
  • 其中一个最有用的方法是 replace_variables, 它允许访问当前可用的变量.
    •   比如我们不知道rfw的哈希方法,可以自己写一个 
      import hashlib
      from robot.libraries.BuiltIn import BuiltIn
      
      class MyModule:
          def getcode(self,password):
              code = hashlib.md5(BuiltIn().replace_variables("${password}").encode())
              print(code.hexdigest())
      *** Test Cases ***
      case1
          Set Global Variable    ${password}        111111
          Getcode     ${password}
      ==============================================================================
      Functest                                                                      
      ==============================================================================
      case1                                                                 | PASS |
      ------------------------------------------------------------------------------
      [info] ${password} = 111111
      [info] 96e79218965eb72c92a549dd5a330112
      Functest                                                              | PASS |
      1 test, 1 passed, 0 failed
      ==============================================================================
  • 一个直接的方式是使用继承来扩展已有库,一个大问题是, 这两个库将很难同时使用. 首先这两个库的同名关键字会产生 冲突, 另外, 这两个库没有共享状态.
    •   比如rfw使用requests不打印请求响应信息,可以重写session类来打印

      ==============================================================================
      Functest                                                                      
      ==============================================================================
      [info] ${data} = {'username': 'admin', 'password': '111111'}
      case1                                                                 b'{"username": "admin", "password": "111111"}'
      {'name': 'admin', 'nickname': '管理员', 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY2NjI4MzI3NCwianRpIjoiMTY0ZmEzYjAtNDI1ZC00YzE1LWEyM2ItOThiMGIzZWY4NDY0IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6MSwibmJmIjoxNjY2MjgzMjc0LCJleHAiOjE2NjYzMDEyNzR9.ndUAu0VmcBKLvS9AGmxb-nufVumA4hR-9qeegKxJ4GI', 'uuid': 1}
      | PASS |
      ------------------------------------------------------------------------------
      Functest                                                              | PASS |
      1 test, 1 passed, 0 failed
      ==============================================================================

  • 内置关键字 Get Library Instance 可以用来获取当前活动的测试库的实例. 该关键字返回的实例与框架自己使用的实例完全一样
    •   比如获取正在运行的Selenium实例获取页面元素

      *** Settings ***
      Library     BuiltIn
      Library    SeleniumLibrary
      Library     util/SeLibExtensions.py
      Suite Teardown      Close All Browsers
      
      *** Variables ***
      ${host}         http://www.baidu.com
      
      *** Test Cases ***
      case1
          Open Browser      ${host}      chrome
          SeLibExtensions.Title Should Be    谷歌

      ==============================================================================
      Functest                                                                      
      ==============================================================================
      [info] Opening browser 'chrome' to base url 'http://www.baidu.com'.
      [info (+2.43s)] 获取的抬头:百度一下,你就知道
      [FAIL] Title '百度一下,你就知道' is not  '谷歌'
      case1                                                                 | FAIL |
      Title '百度一下,你就知道' is not  '谷歌'
      ------------------------------------------------------------------------------
      Functest                                                              | FAIL |
      1 test, 0 passed, 1 failed
      ==============================================================================

  • 导入测试库的另一种方式是使用 BuiltIn 库提供的关键字 Import Library. 该关键字接受库名称以及可能的参数作为它的参数. 被导入的库中的关键字在调用 Import Library 关键字的测试套件中可用。

    •   重写上面的功能,初始化就获取对象,复用对象方法,可以用Import Library在实例生成后导入多个实例,使用 WITH NAME (此处区分大小写) 命名,调用特定实例的方法

*** Settings ***
Library     BuiltIn
Library    SeleniumLibrary
Suite Teardown      Close All Browsers

*** Variables ***
${host}         http://www.baidu.com

*** Test Cases ***
case1
    Open Browser      ${host}      chrome       b1
    ${seleniumlib}      Get Browser Aliases
    Import Library      util/SeLibExtensions.py     SeleniumLibrary     WITH NAME       mydriver
    mydriver.get_session_id
    Open Browser      ${host}      chrome       b2
    Switch Browser    b2
    ${seleniumlib}      Get Browser Aliases
    Import Library      util/SeLibExtensions.py     SeleniumLibrary     WITH NAME       mydriver2
    mydriver2.get_session_id
==============================================================================
Functest                                                                      
==============================================================================
[info] Opening browser 'chrome' to base url 'http://www.baidu.com'.
[info (+4.34s)] ${seleniumlib} = {'b1': 1}
case1                                                                 dd7cf760150bbb2a910e1a355414eda5
[info (+0.01s)] Opening browser 'chrome' to base url 'http://www.baidu.com'.
[info (+9.59s)] ${seleniumlib} = {'b1': 1, 'b2': 2}
ee414a1679bb6013acdcdbc6edefeb82
| PASS |
------------------------------------------------------------------------------
Functest                                                              | PASS |
1 test, 1 passed, 0 failed
==============================================================================

结语

这篇贴子到这里就结束了,最后,希望看这篇帖子的朋友能够有所收获。

如果你觉得文章还不错,请大家 点赞、分享、留言 下,因为这将是我持续输出更多优质文章的最强动力!

------------------------------------------------------------

感谢每一个认真阅读我文章的人!!!

如果下面这些资料用得到的话可以直接拿走:

1、自学开发或者测试必备的完整项目源码与环境

2、测试工作中所有模板(测试计划、测试用例、测试报告等)

3、软件测试经典面试题

4、Python/Java自动化测试实战.pdf

5、Jmeter/postman接口测试全套视频获取

6、Python学习路线图

重点:配套学习资料和视频教学

那么在这里我也精心准备了上述大纲的详细资料包含:电子书,简历模板,各种工作模板,面试宝典,自学项目等。需要的朋友

写在最后,给与的建议:

Robotframework⼊门教程(⼀) 最近⼯作中⽤Robot Framework框架来做⾃动化,所以,花时间学习了⼀下,⽹上好的⽂档不多,⼤多都是复制粘贴如何安装环境。要么就是介绍了⼀堆RIDE 的界⾯,活活把这么强⼤的⼀个⼯具讲成了个photoshop,我⽬前⽤了1个多⽉,这个⼯具很强⼤,简单写两句。 ==安装== ⾸先其实RIDE是个好⼯具,但是安装起来真⼼费劲,当时我的MAC上安装的时候google了两天,⼀个问题接⼀个问题。 我这边呢就不⽤RIDE了,想⽤呢⾃⼰想辙安去。 安装命令: pip install robotframework ==第⼀个testcase== RF的特点什么的就不多说了,⽹上有的是,撸起袖⼦就是⼲。 新建demo.robot⽂件,内容如下。 *** Test Cases *** First Case Log Hello World! warn Second Case ${res} Evaluate 1+2+3 Should Be Equal ${res} 6 Third Case ${res} Evaluate 'i'*3 Length Should Be ${res} 运⾏ robot demo.robot。将得到如下 上⾯的例⼦有三条case,第⼀条调⽤内置关键字Log, 第⼀个参数是"Hello World! " ,第⼆个参数是"warn"。就是简单打印⼀条log,后⾯的是log的等级,默 认输出info以上的log到console,截图中可以看到first case中打印了 Hello World!等级为WARN。 第⼆条case,调⽤内置关键字Evaluate,参数是"1+2+3",结果赋值给变量res(RF的语法是⽤$和⼤括号代表标量变量,还有其他类型的变量以后再说)然后调 ⽤Should Be Equal校验结果是否等于6,因为默认是字符串格式,所以second case 执⾏结果是FAIL。 第三条case,和第⼆条类似,同样调⽤Evalutate 赋值给变量res为"iii",校验变量长度为3,执⾏结果为PASS。 最后三⾏显⽰这次执⾏结果⽣成的⽂件,output.xml,log.html,report.html。打开log⽂件如下,结果报告有什么优点就不说了,⾃⼰去看。output.xml先放放以后 再说。 前⾯说过RF中默认的都是格式是String,那么怎么给关键字传其他的类型,答案是⽤变量。修改second case如下: Second Case ${res} Evaluate 1+2+3 Should Be Equal ${res} ${6} 再次执⾏robot demo.robot 这次的结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值