在培训机构也学不到的Robot Framework自动化测试企业级实战教程

2022-09-28 15:15:46 浏览数 (1)

前言

大家好,我是洋子,今天给大家分享一下Robot Framework自动化测试框架的使用教程,Robot Framework是一个可扩展关键字驱动的测试自动化框架,可用于做接口、UI自动化,并且可以使用 Python 或者Java 去编写测试用例依赖的lib库,是一款非常强大的测试框架

看了网上大量文章,基本都是使用Robot Framework的RIDE来进行测试,RIDE即为Robot的图形化编辑界面,操作起来并不是很方便,所以本文将教大家直接使用PythonRobot命令来进行自动化测试,便于用例执行和扩展,大厂基本都在这样用,便于和CI(持续集成)流水线结合执行测试用例

在编写用例的基础之上,我还会教大家设计、搭建自动化测试框架,满足企业级的自动化测试需求

本期教程包括以下部分内容

  • Robot Framework 环境搭建
  • Robot Framework 关键字参数定义
  • 搭建自动化测试框架
  • 编写测试用例
  • 执行测试用例
  • 生成测试报告

环境搭建

Robot Framework是用Python实现的,也可以在Jython(JVM)和 IronPython(.NET)解释器上运行。在安装框架之前,一个明显的前提条件是安装所需的解释器

本文只介绍使用Python去安装Robot Framework框架以及使用Python去编写robot框架的自定义参数、lib库等,因为这是最主流也是最方便的使用方式

下载、安装Python 3.x

Python 2 在2020年已停止维护,所以建议大家都安装Python 3.x 版本

Unix & Linux 安装 Python

  • 安装方法参考文章 https://www.linuxprobe.com/linux-centos7-python3.html
  • 安装方法参考文章 https://blog.csdn.net/L_15156024189/article/details/84831045

Windows 安装 Python

  • 打开官网下载https://www.python.org/downloads/windows/ 下载安装包
  • 安装方法参考文章 https://www.runoob.com/python/python-install.html

MAC 安装 Python

  • 方法1: 打开官网 https://www.python.org/downloads/mac-osx/ 下载最新版安装包
  • 方法2: 使用 homebrew 安装python3 环境,homebrew安装方法见https://blog.csdn.net/u011035397/article/details/115862286,安装完毕后执行命令 brew install python3即可

安装robotframework库

安装robotframework,最简单的方式是通过pip安装

代码语言:javascript复制
pip install robotframework

安装requests库

python的requests库,用来发送HTTP请求,做接口自动化测试需要使用到

代码语言:javascript复制
pip install requests

在mac 命令行下使用pip命令 前面 还需要加sudo命令,否则会提示无权限

安装selenium2library库

安装 selenium2library库,用来做Web UI自动化测试(若只使用robot框架做接口自动化,此库可不安装)

代码语言:javascript复制
pip install robotframework-selenium2library

到此为止,Robot Framework 框架以及所需要的依赖环境全部安装完毕

关键字参数

前言我们提到Robot Framework是关键字驱动的测试自动化框架,这个关键字可以理解成Robot框架的语法,掌握了关键字的含义,我们才能更好的编写测试用例,在Robot框架中有两类关键字,一类是系统自带的关键字,另一类是自定义关键字。当系统关键字不满足我们的测试需求时,就可以基于Python自定义关键字,然后使用自定义的关键字去编写测试用例

系统关键字

为方便讲解,首先创建三个list变量:list_a、list_b、list_c;以及两个scalar变量(scalar变量就是一种标量变量,存放字符串或者数字):string和name。本节知识可先跳过,后面使用到做参考即可

代码语言:javascript复制
@{list_a}   create list   1   a   ${21}   21   12
@{list_b}   set variable   1.0   a   ${21}   21   21
@{list_c}   create list    

${string}    set variable   pengliwen is in hangzhou   
${name}   set variable   plw 

备注:以下提供的用例都是断言成功

  • should contain 、 should not contain 与should contain x times
代码语言:javascript复制
should contain   ${list_b}   1.0   
should not contain   ${list_b}   1   
should contain x times   ${list_b}   21   2

说明:变量{list_b}包含对象1.0而不包含对象1,且对象21在变量{list_b}出现了两次。

  • should be empty 与 should not be empty
代码语言:javascript复制
should be empty   ${list_c}
should not be empty   ${list_a}

说明:变量{list_c}没有赋值,所以为空;相反,变量{list_a}有赋初始值,故为非空。

  • should be equal 与 should not be equal
代码语言:javascript复制
should be equal   ${list_a[1]}   ${list_b[1]}
should not be equal   ${list_a}   ${list_b}

说明:{list_a[1]}=a,{list_b[1]}=a故两个对象相等;而{list_a}和{list_b}有元素不一致,这两个对象不相等

  • Should Be Equal As Numbers 与 Should not Be Equal As Numbers
代码语言:javascript复制
Should Be Equal As Numbers   ${list_b[0]}   1.0000
Should not Be Equal As Numbers   ${list_b[0]}   1.1

说明:${list_b[0]}=1,忽略精度,故与1.0000相等;而即使是忽略精度,1与1.1还是不相等的;

  • Should Be Equal As Integers与Should not Be Equal As Integers
代码语言:javascript复制
Should Be Equal As Integers   ${list_a[3]}   ${list_b[3]}
Should not Be Equal As Integers   ${list_a[4]}   ${list_b[4]}

说明:{list_a[3]}=21,{list_b[3]}=21,而系统默认为字符串格式的“21”,故需要转化为整数类型,转化为整数后两个对象相等;{list_a[4]}=12,{list_b[4]}=21,即使转化为整数后两个对象依旧是不相等;

  • Should Be Equal As Strings与Should not Be Equal As Strings
代码语言:javascript复制
Should Be Equal As Strings   ${list_a[2]}   ${list_b[2]}
Should not Be Equal As Strings   ${list_a[0]}   ${list_b[0]}

说明:{list_a[2]}={21},{list_b[2]}={21},而均为数值型的21,故需要转化为字符串类型,转化为字符串后两个对象相等;

  • Should Be True与Should not Be True
代码语言:javascript复制
Should Be True   ${list_a[0]} < 10
Should not Be True   ${list_a[0]} < 1

说明:${list_a[0]}=1(字符串类型),其ASCII值比字符串10的ASCII值小;

  • Should start With与Should not start With
代码语言:javascript复制
Should start With   ${string}   peng
Should not start With   ${string}   h

说明:${string}=”pengliwen is in hangzhou“是以peng开头,而非以h开头;

  • Should End With与Should not End With
代码语言:javascript复制
Should End With   ${string}   hangzhou
Should not End With   ${string}   pengliwen

说明:${string}=”pengliwen is in hangzhou“是以hangzhou结尾,而非以pengliwen结尾;

  • should match与should not match
代码语言:javascript复制
should match   ${name}   p??
should not match   ${string}   h?*

说明:模式匹配和shell中的通配符类似,它区分大小写,'*'匹配0~无穷多个字符,“?”单个字符

${name}=plw,由以p开头的三个字母组成

  • Should Match Regexp与Should not Match Regexp
代码语言:javascript复制
Should Match Regexp   ${name}   ^\w{3}$
Should not Match Regexp   ${name}   ^\d{3}$

说明:反斜杠在测试数据是转义字符,因此模式中要使用双重转义;'^'和'$'字符可以用来表示字符串的开头和结尾

${name}=plw,是有三个字母--w{3}组成,而不是由三个数字--d{3}组成。

自定义关键字

除了系统关键字,我们还可以编写Python文件自定义关键字,格式如下

代码语言:javascript复制
import requests
from robot.api.deco import keyword

class HttpLibrary(object):
    """ Http Request Library """

    def __init__(self):
        """ 初始化 session """
        self.session = {}

    @keyword('Create Http')
    def create(self, alias, url, headers=None, cookies=None, timeout=None):
        """ 创建一个 Http 连接代理 """
        pass

    @keyword('Post Http')
    def post(self, alias, path='', data='{}', isJsonStr=False):
        """ 执行 POST 请求 """
		pass
 
    @keyword('Get Http')
    def get(self, alias, path='', data='{}', is_log=True):
        """ 执行 GET 请求 """
		pass
 
    @keyword('Json Post Http')
    def jsonpost(self, alias, path='', data='{}'):
        """ 执行 POST 请求(body为json格式) """
		pass  

上面的Python文件定义了一个类,可以看到该文件当中除了init构造方法,其他每个方法都由keyword装饰器修饰,分别定义了Create HttpPost HttpGet HttpJson Post Http这4个自定义关键字,如果还需要其他自定义关键字,按照这个结构继续添加就行

至于自定义关键字和系统自带的关键字如何使用,在下面 创建测试用例 章节会讲到

搭建测试框架

现在虽然安装好了robotframework的运行环境,也能直接开始编写测试用例,但我们还要想到一个问题,如果用例数量非常庞大怎么管理,工具类的lib库管理等问题,就像设计房子的结构图

我们还需要设计一个简单的测试框架的架构,基于架构去填充自己的测试用例,架构如下:

代码语言:javascript复制
- case目录
	- 模块名目录_01
		-  自动化case_01
		-  自动化case_02
	- 模块名目录_02
- lib目录
  • case目录:用来存放自动化case,被测系统可能涉及的模块较多,所以还建了一个二级目录来管理不同模块的case
  • lib目录:用来放公有的工具类,这些工具类已经封装成自定义关键字,方便用例调用,lib目录下的工具类可以根据自己的需求进行编写,比如操作数据库、发送网络请求、操作列表list、操作字典dict等等

创建测试用例

robotframework框架里定义的一个测试用例,就是一个以robot后缀结尾的文件,通用的用例文件内容结构如下:

代码语言:javascript复制
# -*- coding: robot -*-

*** Settings ***
Documentation    测试集合描述
Library        ./lib/HttpLibrary.py
Library        DateTime
Library        json
Library        Collections

*** Variables ***
${参数1}=   xxx
${参数2}=   yyy

*** Keywords ***
关键字名称
    关键字逻辑

*** Test Cases ***
测试用例标题
    [Tags]    DEBUG
    [Documentation]    测试用例描述
    关键名称 ${参数1} ${参数2}
  • Settings:用于引入资源文件
  • Variables:定义变量,=和变量值之间需要空4个空格
  • Keywords:定义关键字,用于测试用例编写当中
  • Test Cases:测试用例的逻辑,应包含测试用例前置步骤、发送请求、返回结果断言等

但在我们实际编写用例的时候,一个用例并不需要SettingsVariablesKeywordsTest Cases 4个部分都包含,我们可以做一些调整,方便用例管理。具体的调整方法就是,创建一个base.robot,这个用例文件没有具体的case逻辑Test Cases这部分,而是将所有case需要用到的公有信息抽取出来,如需要引入的资源文件等等,这样做可以简化其余具体的case,去掉冗余信息

下面我以一个实际的接口测试自动化案例举例子,base.robot内容如下:

代码语言:javascript复制
# -*- coding: robot -*-

*** Variables ***
# 执行接口自动化的测试环境
${case_httpurl}=    http://ip:port

${url_01}=    api_01?param_1=xxx&param_2=yyyy
${url_02}=    api_02?param_1=xxx&param_2=yyyy
${url_03}=    api_03?param_1=xxx&param_2=yyyy
${url_04}=    api_04?param_1=xxx&param_2=yyyy

&{cookies}=    BDUSS=xxxx

*** Settings ***
Documentation    xxx模块测试用例集合
Library        ./lib/DictLibrary.py
Library        ./lib/ListLibrary.py
Library        ./lib/HttpLibrary.py
Library        ./lib/LiveshowClientCommon.py
Library        ./lib/ImLiveshowCommon.py
Library        ./lib/DBOperation.py
Library        ./lib/YamlSchemaValidatorLibrary.py
Library        DateTime
Library        json
Library        Collections

*** Keywords ***
Init Base
    [Documentation]    全局关键字初始化
    ${headers}    Create Dict    {"Content-type": "application/x-www-form-urlencoded"}
    Create Http    httpProxy    ${case_httpurl}    headers=${headers}    cookies=&{cookies}    timeout=500000

base.robot包含了Variables、Settings、Keywords三个部分,base.robot只是集成用例的公有信息,所以并没有Test Cases这部分

在Variables中,我们定义了3种类型的变量,用来存放测试环境ip和端口、接口path以及cookies

Settings中则是引入lib目录下的工具类,这些工具类里面封装好了自定义参数,也可以引用python自带的工具库DateTimejsonCollections等等。

Keywords中是定义了一个自定义关键字名叫Init Base,这个关键字用于初始化,Init Base关键字的逻辑共3行代码

先看一下第2行(如下图),Create Dict这个自定义关键字是从./lib/DictLibrary.py获取到的,为什么能获取到呢,因为我们在Settings部分用系统关键字Library已经导入该文件了,就和python导入包import作用一样

代码语言:javascript复制
${headers}    Create Dict    {"Content-type": "application/x-www-form-urlencoded"}

对于Create Dict的逻辑如下,传入value参数,经过json反序列化,返回字典类型。所以经过执行上面这段代码后,会给${headers}赋值一个字典类型

代码语言:javascript复制
@keyword('Create Dict')
def create(value=None):
    """ 创建一个字典值 """
    if value is None:
        return {}

    if not isinstance(value, dict):
        try:
            value = eval(value)
        except Exception as e:
            pass

    if not isinstance(value, dict):
        try:
            value = json.loads(value)
        except Exception as e:
            pass
    if not isinstance(value, dict):
        raise Exception('[关键字使用不正确] Create Dict 的参数需为 dict 格式')
    return value

再看下Init Base关键字的第3行代码(如下图),Create Http是一个自定义关键字,从./lib/HttpLibrary.py获取到,传入了5个参数。这里注意一下robot case的变量定义,可以采用“变量标识符”($、@、&、%) 大括号{} 变量名来表示,注意第一个参数,是一个字符串常量httpProxy,并不是一个变量

代码语言:javascript复制
Create Http    httpProxy    ${case_httpurl}    headers=${headers}    cookies=&{cookies}    timeout=500000

到这里base.robot的内容就讲完了,接下来我们看下具体的测试用例case该怎么写,用例代码如下

代码语言:javascript复制
*** Settings ***
Documentation    用例描述
...    author by yangzi
Force Tags     标签名
Resource       base.robot
Suite Setup    Init Base

*** Variables ***

${room_id}=   ''
${im_sdk_version}=   '7700016'

*** Test Cases ***
Normal Procedure
    [Documentation]    用例描述
    [Tags]    P1

    #获取参数
    ${params}=    Create Dict      {'room_id':${room_id},'im_sdk_version':${im_sdk_version}}
    #发送请求,获取结果
    ${res}=    Post Http    httpProxy    ${url_01}   ${params}
    
    # 打印log
    log    ${res}
    
    Should Be Equal As Integers    ${res.json()['errno']}    0      #成功
    Validate With Yaml     ./xxx.yaml    ${res.json()}

这个robot case还是有3部分组成,分别是Settings、Variables、Test Cases。Settings部分使用Resource系统关键字导入base.robot,因为我们要使用到base.robot定义的关键字,Suite Setup也是一个系统关键字,即在执行该用例时,会首先运行此部分,这里我们看到是执行了Init Base关键字,这个关键字就是在base.robot里面定义的

在Test Cases部分,我们首先是组装了参数,然后执行Post Http关键字发送http请求,最后使用系统关键字Should Be Equal As Integers进行结果断言,是否返回结果json当中errno字段是否为0,而这里我们还用到了yaml文件去进行结果断言,yaml文件格式如下:

代码语言:javascript复制
status: 0
errno: 0
msg: success
data:
  msg: ''
  user_cert:
    status: !type_int
  can_live: !type_int
  user_type: !type_int
  can_sale_goods: !py_def >
    def judge_templateid(data):
      if data in (0,1):
        return  True
      return  False

为什么要用yaml断言,是因为某些接口返回字段非常多或者返回字段是列表等等,不太方便直接在case当中直接断言

具体yaml文件的详细使用方法,以及上面使用到的Validate With Yaml自定义参数逻辑,在以后的文章我会单独说明,一般情况下case断言我们使用系统关键字Should Be Equal As Integers或者Should Be Equal就行

执行测试用例

执行用例仅需一条命令即可,常用命令如下:

代码语言:javascript复制
#执行单个case,文件名mysql.robot
 robot -P . ./demo/mysql.robot
#执行demo目录下所有case
 robot -P .  demo/
#执行当前目录下所有case
 robot -P .  ./
#执行当前目录下所有以robot后缀结尾的用例文件
robot -P .  ./*.robot

命令解读

  • robot 是运行命令
  • -P . 是将工作目录指定为用例根目录(无论如何都需要指定为用例根目录)
  • demo/mysql.robot 为要执行的用例

生成测试报告

在执行完测试用例后,我们可以看到执行结果,看到pass就是case运行通过了

同时产生了三个测试报告,可使用浏览器打开。如果我们在编写测试用例时,使用了log关键字,测试报告里面也可以查看到,在case运行失败时,我们可以手动添加log进行调试,非常有用

结尾语

好了,到这里恭喜你已经成功学会了Robot Framework的基本使用方法,本文主要介绍了使用Robot框架去进行接口自动化测试,同样Robot Framework可以结合Selenium、Appium做UI自动化,除此以外,本文还提到接口断言使用Yaml文件,介于篇幅太长,在以后的文章中,我会继续更新。另外本文涉及的代码涉及到公司敏感性,暂不开源,大家可以自己动动手实践

作为一个软件测试人员,除了手工测试外,还是非常有必要去掌握自动化测试,此篇文章凝结了真实企业级自动化测试实战经历,

0 人点赞