httprunner

(仅作为个人笔记,如有雷同,请联系删除。。)

https://www.cnblogs.com/aichixigua12/p/13162479.html

HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求

1、特点:

  1. 继承 Requests 的全部特性,轻松实现 HTTP(S) 的各种测试需求
  2. 采用 YAML/JSON 的形式描述测试场景,保障测试用例描述的统一性和可维护性
  3. 借助辅助函数(debugtalk.py),在测试脚本中轻松实现复杂的动态计算逻辑
  4. 支持完善的测试用例分层机制,充分实现测试用例的复用
  5. 测试前后支持完善的 hook 机制
  6. 响应结果支持丰富的校验机制
  7. 基于 HAR 实现接口录制和用例生成功能(har2case
  8. 结合 Locust 框架,无需额外的工作即可实现分布式性能测试
  9. 执行方式采用 CLI 调用,可与 Jenkins 等持续集成工具完美结合
  10. 测试结果统计报告简洁清晰,附带详尽统计信息和日志记录
  11. 极强的可扩展性,轻松实现二次开发和 Web 平台化

2、安装:

pip install httprunner,安装完成后cmd命令检查:hrun -V

可以用相关命令直接生成对应的项目文件夹hrun –startproject 文件夹(如HttpRunnerDemo,执行命令后可以看到生成对应的目录,在当前目录下。
报错解决:原因是框架的版本升级了。
解决方案:去掉– ,直接用 httprunner startproject HttpRunnerDemo 来创建项目。(hrun不好使)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tQbBp8jp-1649140322343)(images/1n6yJMPwBHSX_DMw_MhFrTaa4-Fcq6vI0QT0pEAcWb0.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yktaLvdf-1649140322346)(images/w75ucF4UZvV4nxd7ziTh1ERBU0SQgelJs46rcEz_9zU.png)]

文件目录结构说明

(1). YAML/JSON:(必须)测试用例文件,一个文件对应一条测试用例。
(2). debugtalk:(可选)脚本函数,存储项目中逻辑运算函数,该文件存在时,将作为项目定位标记,其所在目录被视为项目工程的根路径,该文件不存在时,运行测试的路径将被视为当前工作目录,测试用例文件中的相对路径,如.csv均需基于当前工作目录,运行测试后,测试报告文件夹reports会生成在当前工作目录
(3). .env:(可选)存储项目环境变量
(4). reports、logs:(自动生成)运行后自动生成,无需创建

3、YAML文件:作为测试脚本文件。

YAML文件可以创建为.yml文件,.yml需遵循严格的缩进

  1. 基本语法
    (1). 格式要求K:(空格) v,表示一对键值对,必须要写空格,#表示注释
    (2). 以空格的缩进来控制层级关系,只要是左对齐的一列数据,都是同一个层级的
    (3). 属性和值大小写敏感
    (4). 缩进不能用tab键,手动空格

  2. 注意:
    (1). 对于单个YAML/JSON文件来说,数据存储结构为 list of dict的形式,其中可能包含一个全局配置项(config)和若干个测试步骤(test);
    (2). HttpRunner划分了两层变量空间作用域(context)

    1. config:作为整个测试用例的全局配置项

    2. test测试步骤的变量空间(context)会继承或覆盖config中定义的内容

      注意:若某变量在config中定义了,在某test中没有定义,则该test会继承该变量;若某变量在config和test中都定义了,则该test使用config中定义的变量值,各个测试步骤的变量空间相互堵路,互不影响,如需在多个测试步骤中传递参数值,则需要使用extract关键字,并且只能从前往后传递

    eg:在testcases中建立一个demo的yml文件,把接口测试资料按一定的规则写入:

    注:config中引入的变量:很多接口的公共部分,可以抽离出来放入debugtalk.py

    - config:  # config是接口配置部分
        request:
          headers: $content # 在config中引入变量$host、$content等
          base_url: $host
          url: /commons_service/weather/getWeatherListByLocation?appType=6&requestId=777777
          method: POST
     
    - test:  # test是用例部分
        name: test weather ID1
        request:
          json:
            body: {"lat":"", "lng":"", "city":"武汉市"}
        validate:  # validate是断言部分
          - eq: [status_code,200]
          - eq: [json.msg,"成功"]
     
    - test:
        name: test weather ID2
        request:
          json:
            body: { "lat":"123","lng":"125","city":""}
        validate:
          - eq: [status_code,200]
          - eq: [json.msg,"成功"]
    

4、运行case:

hrun HttpRunnerDemo\testcases\demo_testcase_ref.yml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UpqPA82K-1649140322348)(images/fX8pAMlNeC98o8eZb0BoDeWeAYhSLUNgpVGG8Ut86js.png)]

另还会在logs下生成测试日志: HttpRunnerDemo\logs\77343183-2374-4d6a-a499-6580fbb89b45.run.log,可以打开log查看详情,可以清晰的看到接口返回和断言结果。

注意:感觉是在运行时会把yaml测试文件转换成对应的_test.py文件,可以关注下。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bpfpdPup-1649140322349)(images/xRtpfNtz-k38Y88vFXUBvTrGHRjA9iQwv5lGXY8fTYE.png)]

5、httprunner还支持接口录制

(用抓包工具生成.har文件)后转为可执行的用例(用har2case),最重要的是,测试用例和代码的分离。这样使得稍有编码功底的人迅速上手。

6、简单的接口测试场景:

利用HttpRunner发送请求–(get/post,带参数/不带参数)

eg:伪代码,不执行

### 1.get请求,不带参数,并对响应结果正则表达式提取做断言
- config: 
    name: "get请求,不带参数"
    base_url: http://www.baidu.com

- test: 
    name: "open xxx.."
    request: 
      url: /okhll/
      method: GET
    extract: 
      - code: "status_code"
      - title: 'tid=72872&fid="89" class="st" style="" title="测试">(.+?)</a>'
    validate: 
      - eq: [$code, 200]
      - eq: [$title, '测试']


### 2.get请求,带参数
- config: 
    name: "get请求,带参数"
    base_url: http://www.baidu.com

- test: 
    name: "get access_token"
    request:
      url: /cgi_bin/token
      method: GET
      params: 
        grant_type: 'clcoxxxxxxxxxsla'
        appid: 'wk9jh92m83'
        secret: 'a5d68699c76d986b766e282367378c7627c6c7'
    extract: 
      - access_token: content.access_token
    validate: 
        - eq: ["status_code", 200]
        - eq: [content.expires_in, 7200]


### 3.模拟请求头
- config: 
    name: "发送模拟请求头的请求"
    base_url: "https://www.baidu.com"

- test: 
    name: 请求的对象是百度
    request: 
      url: /
      method: GET
      headers: 
        Accept: */*
        Accept-Encoding: gzip, deflate, br
        Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
        User-Agetn: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
    validate: 
      - eq: [status_code, 200]


### 4.post请求
- config: 
    name: 发送post请求
    basr_url: https://www.baidu.com

- test:
    name: 发送post请求
    request: 
      url: /cgi-bin/tags/create
      method: POST
      params: 
        access_token: $access_token
      json: {
        "open_id": "kshdu7236n1928n17631mh",
        "remark": "luoks"
      }
    validate: 
      - eq: ['status_code', 200]

7、参数说明:

  1. config参数
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fQVLlayL-1649140322350)(images/iw16Dsm_EM6ZKIKnEGmG39HXU7t3Wd0bOdyAatW2NpU.png)]
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qNXb4cl1-1649140322355)(images/jvJH_G8JpmCJ5zicJw88SR7lr5aBdF4YXnYb4-WU2LQ.png)]
    (1). output的用法(也可以用export代替):其作用是输出值,相当于print()函数的输出功能,另一个作用则是可以定义变量时用,经常与extract关键字一起组合使用

    - config: 
        name: "访问百度首页"
        base_url: www.baidu.com
        output: 
          - code
          - title
    
    - test: 
        name: "open baidu first-page"
        request: 
          url: /phpuwk/
          method: GET
        extract:
          - code: "status_code"
          - title: 'tid=72872&fid="89" class="st" style="" title="测试">(.+?)</a>'
        validate:
          ...
    
  2. test参数
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8A0cZDRy-1649140322357)(images/qm-p9doLH9a1XjjvUUBjEdypOEJjPU4IJt_4U-Z0cjs.png)]

    (1). extract关键字:可以提取的关键字为:status_code, cookies, elapsed, headers, content, text, json, encoding, ok, reason, url。支持多种提取方式:

    1. 响应结果为 JSON 结构:可采用==.运算符==的方式,例如headers.Content-Type、content.success
    2. 响应结果为 text/html 结构:可采用正则表达式的方式,例如blog-motto\">(.*)

    (2). request 关键词:包括http请求中的详细内容

    1. headers:请求头部信息
    2. method: 请求方式
    3. url:请求地址
    4. host:请求主机地址
    5. params:GET请求参数
    6. data:表单形式的参数
    7. json:json格式的参数

8、断言:

  1. validate关键字:拿实际结果和期望结果去比较。支持两种格式:
    (1). {"comparator_name": [check_itrm, expect_value]}
    (2). {'check': check_itrm, 'comparator': comparator_name, 'expect': expect_value}
    举例:

    - config: 
        name: "get请求,不带参数"
        base_url: http://www.baidu.com
    
    - test: 
        name: "open xxx.."
        request: 
          url: /okhll/
          method: GET
        validate: 
          - {'check': status_code, 'comparator': eq, 'expect': 200}
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v7mqqMCM-1649140322358)(images/Yq6yhcFgdIQ9aeUVGAXq8lSb32LXSurHvcXDtsm756k.png)]

  2. contains关键字:判断包含的断言。

    1. 使用:- contains: [content, 响应正文中的值],判断响应正文中是否包含了某字符串

    2. 举例:

      - config: 
          name: "get请求,带参数"
          base_url: http://www.baidu.com
      
      - test: 
          name: "get access_token"
          request:
            url: /cgi_bin/token
            method: GET
            params: 
              grant_type: 'clcoxxxxxxxxxsla'
              appid: 'wk9jh92m83'
              secret: 'a5d68699c76d986b766e282367378c7627c6c7'
          extract: 
            - access_token: content.access_token
          validate: 
            - contains: [content, access_token]
      

9、变量的创建及使用:

  1. 定义变量variables关键字定义,export也会定义变量【一个test中赋值之后,可被其他test通过$引用】
  2. 使用变量:$变量名 ,如: $name

10、传参操作:

  1. test中测试步骤之间传参

    - config: 
        name: "访问xxx"
        base_url: www.xxx.com
        export: 
          - token  # 2. 控制台输出变量token的值
    
    - test: 
        name: "获取access_token"
        request: 
          url: /phpuwk/
          method: GET
          params: 
            xxx: xxx
        extract:
          - token: content.access_token  # 1. extract提取access_token的值,并赋值给变量token
        validate:
          ...
    
    - test: 
        name: 查看已经被创建的标签
        request: 
          url: /okhll/
          method: GET
          headers: 
            content-type: alication/json
          params: 
            access_token: "$token"  # 3. 引用token值
        validate:
          ...
    
  2. .env文件存放设置的全局变量参数及参数值,引用方式为: ${ENV(参数名)}

    ## .env
    url = https://api.weixin.qq.com
    
    ## xxx.yml
    - config: 
        name: "引用.env文件传递参数"
        base_url: ${ENV(url)}
    ...
    
  3. debugtalk.py文件:可在这个文件中编写辅助函数,然后进行关联。引用该文件中的函数的方法为:${函数名}

    ## debugtalk.py
    #! /usr/bin/env_python
    # encoding: utf-8
    import requests
    def get_token():
        get_data={"grant_type":"xxx",
                   "appid":"xxx",
                   "secret":"xxxxxxx"}
        respone = requests.get(url='https://api.weixin.qq.com/cgi-bin/token', params=get_data)
        return respone.json()['access_token']
    
    ## xxx.yml
    ...
    - test:
        name: "引用debugtalk.py文件函数传递参数"
        request: 
          url: /cgi-bin/tags/get
          method: GET
          headers: 
            content-type: alication/json
          params: 
            access_token: ${get_token()}  ## 引用debugtalk.py文件函数传递参数
        validate:
          ...
    
  4. 用例之间传参把需要的值都给参数化,然后进行相互调用,可以提高代码复用率
    举例:【注意:这几个过程中,变量名必须保持一致
    (1). 先在test中用extrac关键字提取出token赋值给token_id;
    (2). 然后config中用export关键字输出token_id值;
    (3). 其他test需要引用的情况下,需要先使用variables关键字定义该变量然后再引用

    ## test1.yaml
    - config: 
        name: "访问xxx"
        base_url: www.xxx.com
        export: 
          - token_id  # 2. 控制台输出token_id
    
    - test: 
        name: "获取access_token"
        request: 
          url: /phpuwk/
          method: GET
          params: 
            xxx: xxx
        extract:
          - token_id: content.access_token  # 1. 提取并赋值access_token给token_id
        validate:
          ...
    
    
    ## test2.yaml
    - config: 
        name: "get请求,带参数"
        base_url: ${ENV(url)}
    
    - test:
        name: "调用获取access_token的接口,引用其中的access_token参数"
        testcase: testcases/test1.yaml  # 执行test1.yaml,方便引用其中的access_token参
    
    - test: 
        variables:
          token_id: $token_id  # 3. 定义变量
        name: 查看已经被创建的标签
        request: 
          url: /okhll/
          method: GET
          headers: 
            content-type: alication/json
          params: 
            access_token: $token_id  # 4. 引用变量
        validate: 
          - {'check': status_code, 'comparator': eq, 'expect': 200}
    

11、参数化:

  1. 通过testsuite中编写parameter关键字参数化:从2.0.0版本开始,HttpRunner不再支持在测试文件中进行参数化配置,参数化的功能需要在testsuite中实现,实现的方式为parameters下面写参数,testsuite中执行的时候需要引用testcases中的用例,参数化后需要在testsuite中运行yml文件

    ### testsuit.yml 文件
    config:
      name: 参数化测试套件
    testcases:
      - name: 这里引用testcases中的测试用例
        testcase: testcases/test01.yml  # ----------> 测试用例的绝对路径
        parameters:    # ---------------------------> 设置参数
          serch_word: [baidu, 777, python]  # ------> 参数名:参数列表
    
    
    ### test01.yml 文件
    - config:
        name: 测试用例,被上面测试套件引用
        base_url: https://www.baidu.com
        export: 
          - title
    - test:
        name: 百度搜索
        request: 
          url: /s
          method: GET
          params: 
            wd: $serch_word  # ---------------------> 对testsuit中parameters设置的参数的引用
          header: 
            Accept: xxx
            Accept-Encoding: xxx
            Accept-Language: xxx
            User-Agent: xxx
        extract: 
          - title: <title>(.+?)</title>
        validate: 
          -eq: ["status_code", 200]
    

    (1). testsuite传递多个参数:以-隔开参数,以列表的方式处理【一个list:是一组参数,传递给多个变量;一个-:case执行一次,所谓参数化】

    ### testsuit.yml 文件
    config:
      name: 参数化测试套件
    #testcases:
    #  - name: 这里引用testcases中的测试用例
    #    testcase: testcases/test01.yml  # ----------> 测试用例的绝对路径
    #    parameters:    # ---------------------------> 设置参数
    #      serch_word: [baidu, 777, python]  # ------> 参数名:参数列表   
    testcases:
      - name: 这里引用testcases中的测试用例
        times: 5
        skipIf: [1, 2]
        testcase: testcases/test02.yml  # ----------> 测试用例的绝对路径
        parameters:    # ---------------------------> 设置参数
          serch_word-result:  # --------------> 以-隔开参数,以列表的方式处理:参数1:serch_word,参数2:result
            - [python, python_百度搜索] # ----------> 第一组参数:[参数1,参数2]
            - [chrome, chrome_百度搜索] # ----------> 第二组参数
            - [google, google_百度搜索] # ----------> 第三组参数
    
    
    ### test02.yml 文件
    - config:
        name: 测试用例,被上面测试套件引用
        base_url: https://www.baidu.com
        export: 
          - title
    - test:
        name: 百度搜索
        extract: 
          - title: <title>(.+?)</title>
        request: 
          url: /s
          method: GET
          params: 
            wd: $serch_word  # ---------------------> 引用第一个参数:即-的前半部分,serch_word
          header: 
            Accept: xxx
            Accept-Encoding: xxx
            Accept-Language: xxx
            User-Agent: xxx
        validate: 
          -eq: [$title, $result] # -----------------> 引用第二个参数:即-的后半部分,result
    

    (2). 笛卡尔积的运用:比如测试账号有四种[“test1”, “test2”, “test3”, “test4”],密码也有四种 [“123456”, “123456”, “123456”, “123456”],用笛卡尔积组合的话,就是4*4=16种组合

    ### testsuit.yml 文件
    config:
      name: 参数化测试套件
    testcases:
      - name: 这里引用testcases中的测试用例
        times: 5
        skipIf: [1, 2]
        testcase: testcases/test02.yml  # ----------> 测试用例的绝对路径
        parameters:    # ---------------------------> 设置参数
          user: ["test1", "test2", "test3", "test4"] # 
          passwd: ["123456", "123456", "123456", "123456"] # case中传入$user和$passwd,case会执行16种组合的次数
    
  2. 利用csv文件进行参数化根路径下新建data文件夹–新建info.csv文件,文件中的参数用" , "符号分隔,testsuit中通过P()函数进行引用,case里面需要csv文件中的参数时,则通过 $ 参数名的方法调用,与csv中的参数排列顺序无关,注意参数名称必须与csv表头保持一致

    ### E:\Code_local\HttpRunnerDemo\data\info.csv
    search_word,result  # 搜索参数,预期结果
    taobao,taobao_百度搜索
    python,python_百度搜索
    123456,123456_百度搜索
    charme,charme_百度搜索
    google,google_百度搜索
    
    
    ### testsuit.yml
    config:
      name: 参数化测试套件
    testcases:
      - name: 这里引用testcases中的测试用例
        testcase: testcases/test02.yml
        parameters: 
          search_word-result: ${P(data/info.csv)} # 引用csv文件,csv参数的个数通过-隔开
    
    
    ### test01.yml
    - config:
        name: 测试用例,被上面测试套件引用
        base_url: https://www.baidu.com
        export: 
          - title
    - test:
        name: 百度搜索
        request: 
          url: /s
          method: GET
          params: 
            wd: $serch_word  # ------------> 引用第一个参数:即-的前半部分,serch_word
          header: 
            Accept: xxx
            Accept-Encoding: xxx
            Accept-Language: xxx
            User-Agent: xxx
        extract: 
          - title: <title>(.+?)</title>
        validate: 
          -eq: [$title, $result] 
    
  3. 通过debugtalk实现参数化:(相当于jmeter中的函数助手的功能),与parameters下引用csv一样,debugtalk参数化的数据也是一个列表,使用${函数}引用debugtalk中的函数

    ### debugtalk.py
    # "随机在某最小值和某最大值的范围内生成多少个整数组成的列表"
    def get_randomint(min, max, count=None):
        randomint_list = []
        for i in range(count):
            randomint_list.append(random.randint(min, max))
        return randomint_list
    
    def setup_case(case_name):
        print("测试用例 s% 开始执行" % case_name)
    def teardown_case(case_name):
        print("测试用例 s% 执行结束" % case_name)
    def setup_step(case_step):
        print("测试步骤 s% 开始执行" % case_step)
    def teardown_step(case_step):
        print("测试步骤 s% 执行结束" % case_step)
    
    if __name__ == "__main__":
        print(get_randomint(1, 20, 10))
    
    
    ### testsuit.yml
    config:
      name: 参数化测试套件
    testcases:
      - name: 这里引用testcases中的测试用例
        testcase: testcases/test01.yml
        parameters: 
          search_word: ${get_randomint(1, 20, 5)} # 引用debugtalk中的函数
    
    
    ### test01.yml
    - config:
        name: 测试用例,被上面测试套件引用
        base_url: https://www.baidu.com
    - test:
        name: 百度搜索
        request: 
          url: /s
          method: GET
          params: 
            wd: $serch_word 
          header: 
            ...
    

12、跳过执行:只能在testcases中设置

  1. 无条件跳过skip
  2. 条件为真跳过skipIf
  3. 条件为假跳过skipUnless
### test01.yml
- config:
    name: 测试用例,被测试套件引用
    base_url: https://www.baidu.com
- test:
    skip: 无条件跳过  # ---------->   a. 无条件跳过:skip
    name: 百度搜索
    request: 
      ...
    validate: 
      -eq: ["status_code", 200] 

- test:
    skipIf: 百度搜索2  # --------->  a. 条件为真跳过:skipIf,非空、非0、True时跳过执行
    name: 百度搜索2
    request: 
      ...
    validate: 
      -eq: ["status_code", 200] 

- test:
    skipUnless:      # ---------->    a. 条件为假跳过:skipUnless,空、0、False时跳过执行
    name: 百度搜索3
    request: 
      ...
    validate: 
      -eq: ["status_code", 200] 

13、重复执行:times 参数,用例中可以设置用例运行的次数

### test01.yml
- config:
    name: 测试用例,被测试套件引用
    base_url: https://www.baidu.com
- test:
    skipUnless: 1
    times: 5   # -----------> times设置case运行次数
    name: 百度搜索
    request: 
      ...
    validate: 
      -eq: ["status_code", 200] 

14、用例分层:

Httprunner项目分层为 api接口层testcases用例层testsuite测试套件层
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N2zdUiJs-1649140322360)(images/wsaOtbonP70Vz-MgkYvU15FwtCZd4nTv-V6JALxExvk.png)]

  1. api接口层不用在里面加特殊细节的断言,断言接口能否请求通即可。新建api文件夹,下面新建一个yml文件进行接口api的编写。举例:

    ### E:\Code_local\HttpRunnerDemo\api\test.yml
    name: "获取access_token"
    base_url: ${ENV(url)}
    
    request: 
      url: /cgi-bin/token
      method: GET
      params: 
        grant_type: ${ENV(grant_type)}
        appid: ${ENV(appid)}
        secret: ${ENV(secret)}
    validate:
      - eq: [status_code, 200]
    
  2. testcases用例层直接调用接口层中的yml文件执行,细节断言可在这里编写,同时也可以调用其他用例或者其他用例的参数执行

    ### test01.yml
    - config:
        name: case中调用api文件中的yml文件执行
    - test: 
        name: step01:执行获取token的接口
        api: api/test.yml   # ------------------> 只需要写被调用的api目录下的yml绝对路径即可
        validate: 
          - contains: [content, access_token] 
    
  3. testsuite测试套件层新建testsuites目录存放测试套件,将测试用例整合起来执行

    ### testsuit01.yml
    config: 
      name: 测试套件整合测试用例进行执行
    
    testcases:
      - name: 调用testcases中的用例执行
        testcase: testcases/test01.yml  # ----> 被调用case的绝对路径
    

15、case之间的相互调用:

可以通过调取用例和调取用例之中的参数进行调用

  1. 用例之间的简单调用testcase关键字,直接给被调用用例的绝对路径

    ### test01.yml
    - config:
        name: 测试用例,被测试套件引用
        base_url: https://www.baidu.com
    
    - test: 
        name: 调用其他用例
        testcase: testcases/test02.yml  # -------> 被调用用例的绝对路径
    
    - test:
        ...
    
  2. 用例之间传参的调用:参考【10.4:用例之间传参】

来源:你们的好朋友大强

物联沃分享整理
物联沃-IOTWORD物联网 » httprunner

发表评论