httprunner V4.3.5 安装与使用--快速上手(超详细-超长篇)

一、Httprunner介绍

1、什么是Httprunner

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

核心特征:

  1. 继承 Requests 的全部特性,轻松实现 HTTP(S) 的各种测试需求
  2. 测试用例与代码分离,采用YAML/JSON的形式描述测试场景,保障测试用例具备可维护性
  3. 测试用例支持分层机制,充分实现测试用例的复用
  4. 测试用例支持参数化和数据驱动机制
  5. 使用 skip 机制实现对测试用例的分组执行控制
  6. 支持热加载机制,在文本测试用例中轻松实现复杂的动态计算逻辑
  7. 基于 HAR 实现接口录制和用例生成功能(har2case)
  8. 结合 Locust 框架,无需额外的工作即可实现分布式性能测试
  9. 执行方式采用 CLI 调用,可与 Jenkins 等持续集成工具完结合
  10. 测试结果统计报告简洁清晰,附带详尽统计信息和日志记录
  11. 具有可扩展性,便于扩展实现 Web 平台化(HttpRunnerManager)

2、HttprunnerV4版本介绍

  • 开发语言:Golang + Python
  • 脚本转换工具:HAR/Postman/Swagger/Curl
  • 脚本格式类型:YAML/JSON/pytest/gotest
  • 脚本执行引擎:Go 自研 + Python pytest
  • 接口测试报告:html 自研(Go template) + pytest-html/allure
  • 性能测试引擎:Go Boomer
  • 运行环境依赖:Go 引擎无需依赖、pytest 引擎依赖 Python 3.7+
  • 安装部署方式: curl/wget/pip

v1/v2/v3/v4 版本对比概览:
在这里插入图片描述

3、HttprunnerV4版本Go & Python 功能对比

在这里插入图片描述

4、Httprunner 与 unittest & pytest 的区别

使用语言和用途:

  • Httprunner‌ 是一个面向HTTP(S)协议的通用开源测试框架,支持YAML、JSON等多种格‌httprunner‌主要是一个用于接口自动化测试和性能测试的框架,支持HTTP/HTTPS/HTP2/WebSocket/TCP/RPC协议,使用YAML或JSON格式的文件描述测试用例,特别适合接口测试和性能测试。
  • unittest‌是Python自带的测试框架,主要用于编写单元测试,提供测试用例的编写、测试套件的组织、测试执行和断言等基本功能。
  • pytest‌也是一个用于Python的测试框架,可以进行单元测试和功能测试,具有更简洁的语法和灵活的自动发现测试功能,支持参数化测试、测试装饰器和插件机制等。

学习曲线和复杂性:

  • httprunner‌的语法相对简单,测试脚本编写和维护较为容易,适合初学者快速上手
  • unittest‌语法相对繁琐,但在Python标准库中集成,无需额外安装,对于熟悉Python的开发者来说,这是一个优势。
  • pytest‌的语法简单易懂,学习曲线较为平缓,支持多种测试方式和插件,可以满足复杂的测试需求。

功能和特性:

  • httprunner‌支持请求参数化、断言和全局变量等功能,提供丰富的测试报告和日志功能
  • unittest‌提供了测试用例的编写、测试套件的组织、测试执行和断言等基本功能,适合进行单元测试
  • pytest‌支持参数化测试、fixture、mock等多种功能,可以生成详细的测试报告,支持并发测试,提高测试效率。‌

优劣势总结:

  • httprunner‌的优势在于其简单的语法和易用性,并支持多协议HTTP(S)/HTP2/WebSocket/TCP/RPC等,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。
  • unittest‌作为Python自带的测试框架,无需额外安装,但语法相对繁琐。它适合进行单元测试,是Python开发者熟悉的选择。
  • pytest‌以其简洁的语法和强大的功能受到开发者的青睐,支持多种测试方式和插件,可以满足复杂的测试需求。劣势在于对于需要大量IO操作的测试可能存在性能瓶颈

二、安装

1、Httprunner下载

  • 1.1、一键安装部署(MAC):
$ bash -c "$(curl -ksSL https://httprunner.com/script/install.sh)"

如报错提示:无权限则使用sudo命令进行安装:

sudo bash -c "$(curl -ksSL https://httprunner.com/script/install.sh)"
  • 检查httprunner安装版本:
httprunner -V or hrun -V 

在这里插入图片描述

出现版本号即安装成功。

  • 检查hrp是否安装成功:
hrp -h

出现下图则安装成功
在这里插入图片描述

  • 1.2、通过pip安装:(通用Mac&Windows):
    建议:安装到虚拟环境下,这样可切换使用不同版本的httprunner
pip install httprunner==4.3.5   //指定版本安装,不加默认下载最新

查看版本:

hrun -V or httprunner -V     

“V”一定要大写,不然如下图报错:
在这里插入图片描述

  • 常见报错:You should consider upgrading via the ‘python -m pip install --upgrade pip’ command.
    You are using pip version 10.0.0, however version 20.0.0 is availa
    • 解决方案:
python -m pip install --upgrade pip     //更新升级pip

升级后依然下载失败,可能pip源内找不到httprunner(Windows常见),更新pip的镜像源即可:

pip install -i https://pypi.douban.com/simple httprunner    //豆瓣镜像源
pip install -i https://pypi.tuna.tsinghua.edu.cn httprunner  //清华大学镜像源

2、Hrp下载

1. 下载hrp
安装httprunner V4.3.5后,还无法使用hrp命令行工具,需要下载编译产物,在 GitHub Releases
页面中自行选择版本进行下载:
在这里插入图片描述
2. 配置hrp的环境变量:

  • Mac:打开终端进入配置
vim ~/.bash_profile    //如果使用的是bash shell 
vim ~/.zshrc	     //如果使用的是zsh shell

进入后添加环境变量:(vim:敲“i”->Enter进入编辑),将以下代码添加进环境变量

export PATH="/usr/local/hrp/bin:$PATH"    // 该路径 /usr/local/hrp/bin/hrp 为hrp的文件路径

保存并关闭文件。(vim:保存退出=>Esc–>:wq–>Enter 保存并退出)

生效配置:

source ~/.bash_profile
source ~/.zshrc

验证环境变量配置是否成功:

hrp -h  or  hrp -v

在这里插入图片描述
在这里插入图片描述

  • Windows配置hrp环境变量:
    将下载的包解压后的hrp.exe放在C盘httprunner文件目录下(自定义目录)在【我的电脑=>属性=>高级系统设置=>环境变量=>系统变量】,在PAHT下新 增变量:C:\httprunner 确认保存即可。
    在这里插入图片描述
    验证环境变量:
hrp -h  or  hrp -v

出现版本号 or 出现帮助页面即可,参考以上。

三、快速上手使用

1、创建手脚架项目

  • 新增手脚架项目:
    使用以下命令新增Httprunner项目并命名为demo:
hrp startproject demo

如下图即新增成功:
在这里插入图片描述

打开demo项目如下图:
在这里插入图片描述

2、录制生成Har文件

  • Charles 录制 HAR 文件:(fiddler & 浏览器开发者模式F12均可抓包导出为har文件)
    以下采用 Charles 等抓包工具为例: 抓取接口导出
    在这里插入图片描述
    存为har格式文件:
    在这里插入图片描述

3、将Har转换成测试用例

  • HttpRunner4.3.5将所有的转换功能都集中在 hrp convert 一个指令中。通过执行 hrp convert -h 可以查询该指令的功能简介、用法和各个选项的介绍:
hrp convert --from-har xxx.har    //将HAR文件默认转换成转换成Json文件      文件名为xxx_test.json
hrp convert --from-har xxx.har --to-yaml   //将HAR文件转换成YAML文件     文件名为xxx_test.yaml
hrp convert --from-har xxx.har --to-json   //将HAR文件转换成Json文件     文件名为xxx_test.json
hrp convert --from-harxxx.har --to-pytest   //将HAR文件转换成pytest文件  文件名为xxx_test.py

在这里插入图片描述

  • 注释:执行hrp convert --from-har xxx.har --to-pytest命令,会先将 xxx.har转化成xxx_test.json,然后再将xxx_test.json转化成xxx_test_test.py
  • hrp convert 指令支持指定目录输出,–output-dir 后接测试用例的期望输出目录的路径,用于将转换生成的测试用例输出到对应的文件夹:
hrp convert --from-har xxx.har --to-pytest --output-dir demo/cases   //输入文件到当前目录下的demo/cases文件夹中

如下:
在这里插入图片描述

  • 执行测试用例:
    **JSON/YAML(/pytes)**类型的测试用例文件,httprunnerV4.3.5使用hrp run 命令执行:
hrp run xxx.json           ##执行json测试用例   
hrp run xxx.yaml          ##执行yaml测试用例
hrp run testcases/       ##执行testcases文件下所有测试用例

pytest文件可通过pytest命令执行改测试用例文件pytest xxx.py

目前的 HttpRunner 支持运行 pytest 的测试用例进行接口测试。由于 HttpRunner wraps pytest,因此pytest 所有的参数都可以与 hrp 命令一起使用。
在这里插入图片描述

4、手工编写测试用例

pytest 、 YAML 和 JSON 格式的测试用例完全等价,包含的信息内容也完全相同,在httprunner中,测试用例组织主要基于三个概念

  • 1测试用例集(testsuite):对应一个YAML/JSON/Python文件,包含单个或多个测试用例文件。通 俗来将,测试用例集就是「一堆」测试用例。对应地,HttpRunner 除了支持指定单个文件来运行某一测试用例,也支持指定多个文件或指定文件夹来运行一整个测试用例集。
  • 测试用例(testcase): 对应一个YAML/JSON/Python文件,包含单个或多个测试步骤。
  • 测试步骤(teststep): 对应YAML/JSON/Python中 teststeps 下的一个节点,描述单次接口测试 的全部内容,包括发起接口请求、解析响应结果、检验结果等。

pytest 、 YAML 和 JSON 格式的测试用例,用例结构整体结构都包含两部分:

  • config: 每个测试用例都必须有config部分,作为整个测试用例的全局配置项,用于配置用例:
    在这里插入图片描述

  • teststeps:包含测试步骤相关信息,测试用例存在顺序关系,运行时将从前往后依次运行 各个测试步骤,其中步骤可以引用其他测试用例:
    在这里插入图片描述

示例:
request.yaml

config:
    name: test
    variables: {}
    verify: false

teststeps:
    - name: "test"
      request:
        method: GET
        url: http://127.0.0.1:8080/api/test/
        params:
            action: list_course
            pagenum: "1"
            pagesize: "20"
        headers:
            Accept: application/json, text/plain, */*
            Accept-Encoding: gzip, deflate, br
            Accept-Language: zh-CN,zh;q=0.9
            Connection: keep-alive
            Host: 127.0.0.1:8080
            Referer: http://127.0.0.1:8080/mgr/test/index.html
            User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36
            X-CSRFToken: ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d
        cookies:
            csrftoken: ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d
            sessionid: b1g42w3ynatxpphy0fhahpdi7g4pn2vg
      extract:
      	  msg: body.msg
      	  cookie: header.cookie
      validate:
        - check: status_code
          assert: equals
          expect: 200
          msg: assert response status code
        - eq: ["body.msg","成功"]

request.py

from httprunner import HttpRunner, Config, Step, RunRequest


class TestCaseRequestsTest(HttpRunner):
    config = (
        Config("request methods testcase with functions")
    )

    teststeps = [
        Step(
            RunRequest("")
            .get("http://127.0.0.1:8080/api/test/")
            .with_params(**{
                "action": "list_course",
                "pagenum": 1,
                "pagesize": 20
            })
            .with_headers(**{
                "Accept": "application/json, text/plain, */*",
                "Accept-Encoding": "gzip, deflate, br",
                "Accept-Language": "zh-CN,zh;q=0.9",
                "Connection": "keep-alive",
                "Host": "127.0.0.1:8080",
                "Referer": "http://127.0.0.1:8080/mgr/test/index.html",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36",
                "X-CSRFToken": "ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d",
            })
            .with_cookies(**{
                "csrftoken": "ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d",
                "sessionid": "b1g42w3ynatxpphy0fhahpdi7g4pn2vg"
            })
            .extract()
            .with_jmespath("body.msg", "msg")
            .with_jmespath("header.cookie", "cookie")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.msg", "成功")
        )
    ]


if __name__ == "__main__":
    TestCaseRequestsTest().test_start()

四、变量 & 提取 & 断言 & 辅助函数 & 参数化 & 环境变量 & 引用其他用例 & 上传文件等的使用

1、变量(variables)

前言:声明变量和引用是经常用到的,引用变量方式有两种:$var 或 ${var} ,通过关键字variables 定义变量主要在config和step中,这两者的区别如下:

  1. 在 config 中定义的变量为全局变量的,范围比较大,也就是整个测试用例(testcase)的所有地方都 可以引用;
  2. 在 step 中定义的变量为局部变量,范围比较小,局限于当前测试步骤(teststep)

示例:

config:
    name: '定义变量:base_url、Accept、X-CSRFToken'
    variables: {
                 base_url: http://127.0.0.1:8080/api/test/,
                 Accept: 'application/json, text/plain, */*',
                 X-CSRFToken: ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d
    }
    verify: false

teststeps:
    - name: "引用config内的变量"
      request:
        method: GET
        url: $base_url     ## 引用config内的base_url
        params:
            action: list_course
            pagenum: "1"
            pagesize: "20"
        headers:
            Accept: ${Accept}   ## 引用config内的Accept
            Accept-Encoding: gzip, deflate, br
            Accept-Language: zh-CN,zh;q=0.9
            Connection: keep-alive
            Host: 127.0.0.1:8080
            Referer: http://127.0.0.1:8080/mgr/test/index.html
            User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36
            X-CSRFToken: $X-CSRFToken  ## 引用config内的X-CSRFToken
        cookies:
            csrftoken: ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d
            sessionid: b1g42w3ynatxpphy0fhahpdi7g4pn2vg
      extract:
      	  msg: body.msg
      	  cookie: header.cookie
      validate:
        - check: status_code
          assert: equals
          expect: 200
          msg: assert response status code
        - eq: ["body.msg","成功"]

注释:config 全局变量和 step局部变量名最好不要相同,当出现相同时,step变量优先级大于config变量。

2、提取(extract)

  • extract:V4支持2种响应结果字段提取方式:

    1. jmespath 表达式:响应结果为 JSON 结构,采用 jmespath 表达式进行参数提取,参考教程
    2. 正则表达式(regex):返回的非JSON 格式,可以用正则表达式(regex) 提取。需要具备一 定的正则知识。
  • extract 提取的对象有5种类型:

    1. headers:从响应 headers 中提取字段,例如 headers.name
    2. cookies:从响应 cookies 中提取字段,例如 cookies.Token
    3. body:从响应 body 中提取字段,例如 body.args.foo1
    4. status_code:提取响应状态码,例如 200、404
    5. proto:提取协议类型,例如 “HTTP/2.0”、“HTTP/1.1

示例:

config:
    name: "request methods testcase with functions"
    variables:
        foo1: config_bar1
        foo2: config_bar2
        expect_foo1: config_bar1
        expect_foo2: config_bar2
    headers:
        User-Agent: ${get_user_agent()}
    verify: False
    export: ["foo3"]
teststeps:
-
    name: '测试提取返回的结果'
    variables:
        foo1: ${ENV(USERNAME)}
        foo2: bar21
        sum_v: "${sum_two_int(10000000, 20000000)}"
    request:
        method: GET
        url: $base_url/get
        params:
            foo1: $foo1
            foo2: $foo2
            sum_v: $sum_v
    extract:
        foo3: "body.args.foo3"     ## 提取foo3的值,body.args.foo3
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.args.foo1", "debugtalk"]
        - eq: ["body.args.sum_v", "30000000"]
        - eq: ["body.args.foo2", "bar21"]
-
    name: post raw text
    variables:
        foo1: "bar12"
        foo3: "bar32"
    request:
        method: POST
        url: $base_url/post
        headers:
            Content-Type: "text/plain"
            cookies: 35c394b6b97ce682c91bd79aedf2c0a987c6a9d419b47651f8df25268bb883b8b364ff67a1cec3d2d1cef94573
        body: "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
    extract:
        Content-Type: headers.Content-Type   ## 提取headers内的Content-Type
        cookies: headers.cookies             ## 提取headers内的cookies
        status_code: body.code               ## 提取body的返回状态码
        foo2: body.args.foo2                 ## 提取body内foo2的值
        proto: request.method                ## 提取请求内的请求方式

    validate:
        - eq: ["status_code", 200]
        - eq: ["body.data", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32."]
        

3、断言(validate)

断言validate:
使用jmespath提取 JSON 响应正文(text/html 格式用正则表达式提取)并使用预期值进行验证。

  • 提取结果:jmespath 表达式或正则表达式提取,更多细节参考JMESPath 教程
  • 预期值:这里也可以使用指定的预期值、变量或函数引用

示例:

config:
    name: "request methods testcase with functions"
    variables:
        foo1: config_bar1
        foo2: config_bar2
        expect_foo1: config_bar1
        expect_foo2: config_bar2
    headers:
        User-Agent: ${get_user_agent()}
    verify: False
    export: ["foo3"]
teststeps:
-
    name: '断言方式'
    variables:
        foo1: ${ENV(USERNAME)}
        foo2: bar21
        sum_v: "${sum_two_int(10000000, 20000000)}"
    request:
        method: GET
        url: $base_url/get
        params:
            foo1: $foo1
            foo2: $foo2
            sum_v: $sum_v
    extract:
        foo3: "body.args.foo3"     ## 提取foo3的值,body.args.foo3
        
#    validate:                      ## 这种方式也可进行断言
#        - check: status_code               
#          assert: equals
#          expect: 200
#          msg: assert response status code
#        - check: headers."Content-Type"
#          assert: equals
#          expect: application/json;charset=UTF-8
#          msg: assert response header Content-Type
    validate:                           ##常用方式
        - eq: ["status_code", 200]
        - eq: ["body.args.foo1", "debugtalk"]
        - eq: ["body.args.sum_v", "30000000"]
        - eq: ["body.args.foo2", "bar21"]

断言方式:
在这里插入图片描述

4、辅助函数(debugtalk)

前言:v4支持go语言和Python语言写辅助函数,在根目录编辑debugtalk.py文件写辅助函数实现自动化生成动态参数:(主要最后三种方法:账号密码参数化、随机数、时间戳

import datetime
import logging
import time
from typing import List
import string
import random


def get_user_agent():
    return "PpStore/10.7.5(client/phone; iOS 17.5.1; iPhone13,1)"


def sleep(n_secs):
    time.sleep(n_secs)


def sum(*args):
    result = 0
    for arg in args:
        result += arg
    return result


def sum_ints(*args: List[int]) -> int:
    result = 0
    for arg in args:
        result += arg
    return result


def sum_two_int(a: int, b: int) -> int:
    return a + b


def sum_two_string(a: str, b: str) -> str:
    return a + b


def sum_strings(*args: List[str]) -> str:
    result = ""
    for arg in args:
        result += arg
    return result


def concatenate(*args: List[str]) -> str:
    result = ""
    for arg in args:
        result += str(arg)
    return result


def setup_hook_example(name):
    logging.warning("setup_hook_example")
    return f"setup_hook_example: {name}"


def teardown_hook_example(name):
    logging.warning("teardown_hook_example")
    return f"teardown_hook_example: {name}"


def get_username_password():
    """账号密码参数化"""
    return [
        {"username": "admin1", "password": "123334"},
        {"username": "admin2", "password": "123444"},
        {"username": "admin3", "password": "123555"},
        {"username": "admin4", "password": "123666"}
    ]


def generate_random_string(length):
    """随机数"""
    letters = string.ascii_letters + string.digits + "!@#$%^&*()"
    return ''.join(random.choice(letters) for _ in range(length))


def get_timestamp():
    """时间戳"""
    print("timetap", str(int(datetime.datetime.now().timestamp() * 1000)))
    return str(int(datetime.datetime.now().timestamp() * 1000))

实例引用debugtalk辅助函数:与引用变量发法一致,如下get_user_agent()、get_timestamp()

config:
    name: "request methods testcase with functions"
    variables:
        foo1: config_bar1
        foo2: config_bar2
        expect_foo1: config_bar1
        expect_foo2: config_bar2
    headers:
        User-Agent: ${get_user_agent()}    # 引用获取debugtalk函数内的get_user_agent()方法
    verify: False
    export: ["foo3"]
teststeps:
-
    name: '引用辅助函数debugtalk'
    variables:
        foo1: ${ENV(USERNAME)}
        foo2: bar21
        sum_v: "${sum_two_int(10000000, 20000000)}"
    request:
        method: GET
        url: $base_url/get
        params:
            timestamps: $get_timestamp()  #引用获取debugtalk函数内的get_timestamp()方法
            foo1: $foo1
            foo2: $foo2
            sum_v: $sum_v
    extract:
        foo3: "body.args.foo3"     ## 提取foo3的值,body.args.foo3
    validate:                           ##常用方式
        - eq: ["status_code", 200]
        - eq: ["body.args.foo1", "debugtalk"]
        - eq: ["body.args.sum_v", "30000000"]
        - eq: ["body.args.foo2", "bar21"]

5、参数化(parameters)

前言:实现参数化使用parameters关键字,数据源有三种方式:

  1. 在 yaml 文件中直接写测试数据源,最为简单,适合参例表比较少的场景。
  2. 测试数据源写到 csv 文件,该种方式需要准备 CSV 数据文件,适合数据量比较大的情况。
  3. 自定义函数,函数返回列表形式数据,该种方式最为灵活,可通过自定义 Python 函数实现任意场景的数据驱动机制,当需要动态生成参数列表时也需要选择该种方式。

单个参数进行参数化:

config:
    name: "request methods testcase with functions"
    verify: False
    export: ["foo3"]
    parameters: 
        foo1: [123456, 1234567, 12345678, 123456789]
        foo2: [111111, 22222222, 3333333, 444444444]
teststeps:
-
    name: 'parameters参数化-单个'
    variables:
        sum_v: "${sum_two_int(10000000, 20000000)}"
    request:
        method: GET
        url: $base_url/get
        params:
            timestamps: $get_timestamp()  #引用获取debugtalk函数内的get_timestamp()方法
            foo1: ${foo1}
            foo2: $foo2
            sum_v: $sum_v
    extract:
        foo3: "body.args.foo3"     ## 提取foo3的值,body.args.foo3
    validate:                           ##常用方式
        - eq: ["status_code", 200]
        - eq: ["body.args.foo1", "debugtalk"]
        - eq: ["body.args.sum_v", "30000000"]
        - eq: ["body.args.foo2", "bar21"]

以上执行后会生成4条case。

关联性参数化

config:
    name: "request methods testcase with functions"
    verify: False
    export: ["foo3"]
    parameters:
        foo1-foo2:  # 关联性参数
            - [123456, 111111]
            - [1234567, 22222222]
            - [12345678, 3333333]
            - [123456789, 444444444]
#        foo1: [123456, 1234567, 12345678, 123456789]
#        foo2: [111111, 22222222, 3333333, 444444444]
teststeps:
-
    name: 'parameters参数化-关联性参数'
    variables:
        sum_v: "${sum_two_int(10000000, 20000000)}"
    request:
        method: GET
        url: $base_url/get
        params:
            timestamps: $get_timestamp()  #引用获取debugtalk函数内的get_timestamp()方法
            foo1: ${foo1}
            foo2: $foo2
            sum_v: $sum_v
    extract:
        foo3: "body.args.foo3"     ## 提取foo3的值,body.args.foo3
    validate:                           ##常用方式
        - eq: ["status_code", 200]
        - eq: ["body.args.foo1", "debugtalk"]
        - eq: ["body.args.sum_v", "30000000"]
        - eq: ["body.args.foo2", "bar21"]

关联性参数常用于账号密码:

###几组账号密码中,如果不同账号对应不同密码,这时候就得用关联性参数化了:

config:
  name: '关联性参数化-常用于账号密码--与笛卡尔积组合一至'
  parameters:
    username-password:
      - [ admin1, "123334" ]
      - [ admin2, "123444" ]
      - [ admin3, "123555" ]
      - [ admin4, "123666" ]

teststeps:
-
  name: '关联性参数化-常用于账号密码--与笛卡尔积组合一至'
  request:
    method: POST
    url: ${ENV(base_url_test)}/login
    params:
      username: ${username}
      password: $password
  validate:
    - eq: [status_code, 200]
    - eq: [headers."Content-Type", "application/json"]

笛卡尔积组合:
假如测试用例中定义了多个参数,那么测试用例在运行时会对参数进行笛卡尔积组合,覆盖所有参数组合情况。

  • 账号有4种[admin1, admin2, admin3, admin4],
  • 密码有4种 [“123456”, “123456”, “123456”, “123456”]
  • 用笛卡尔积组合的话,就是4*4=16种组合
###几组账号密码中,如果不同账号对应不同密码,这时候就得用关联性参数化了:

config:
  name: '笛卡尔积参数化组合'
  parameters:
    username-password:
      - [ admin1, "123334" ]
      - [ admin2, "123444" ]
      - [ admin3, "123555" ]
      - [ admin4, "123666" ]

teststeps:
-
  name: '笛卡尔积参数化组合'
  request:
    method: POST
    url: ${ENV(base_url_test)}/login
    params:
      username: $username
      password: ${password}
  validate:
    - eq: [status_code, 200]
    - eq: [headers."Content-Type", "application/json"]

CSV文件:对于 CSV 数据源文件,需要遵循如下几项约定的规则:

  1. CSV 文件中的第一行必须为参数名称,从第二行开始为参数值,每个(组)值占一行;
  2. 若同一个 CSV 文件中具有多个参数,则参数名称和数值的间隔符需实用英文逗号;
  3. 在 YAML/JSON 文件引用 CSV 文件时,文件路径为基于项目根目录(debugtalk.py 所在路径)的相对路径。

示例:
test_data.csv

username,password
admin1,123334
admin2,123444
admin3,123555
admin4,123666

引用csv文件:

###几组账号密码中,如果不同账号对应不同密码,这时候就得用关联性参数化了:

config:
  name: 'csv文件参数化案例'
  parameters:
    username-password: ${P(data/test_data.csv)}

teststeps:
-
  name: 'csv文件参数化案例'
  request:
    method: POST
    url: ${ENV(base_url_test)}/login
    params:
      username: $username
      password: ${password}
  validate:
    - eq: [status_code, 200]
    - eq: [headers."Content-Type", "application/json"]

外部函数(debugtalk)参数化:用 debugtalk.py 中自定义的函数生成参数列表,生成的参数列表必须为 list of dict 的数据结构:
需对 username、password 进行参数化数据驱动,那么就可以在 debugtalk.py 中定义一个函数,返回参数列表。
debugtalk.py

def get_username_password():
    """账号密码参数化"""
    return [
        {"username": "admin1", "password": "123334"},
        {"username": "admin2", "password": "123444"},
        {"username": "admin3", "password": "123555"},
        {"username": "admin4", "password": "123666"}
    ]

示例:

config:
  name: 'debugtalk辅助函数参数化'
  parameters:
    username-password: $(get_username_password())
teststeps:
-
  name: 'debugtalk辅助函数参数化'
  request:
    method: POST
    url: ${ENV(base_url_test)}/login
    params:
      username: $username
      password: ${password}
  validate:
    - eq: [status_code, 200]
    - eq: [headers."Content-Type", "application/json"]

6、环境变量(.env)

在前面最初新建httprunner项目后,在根目录下自动生成.env文件,V4版本中内置了函数 ENV 读取环境变量的值,可直接使用${ENV(key)}进行引用。
.env

base_url_test=http://127.0.0.1:8080/api/test/
USERNAME=admin
PASSWORD=123456

引用:

config:
  name: '引用.env环境变量内的值'

teststeps:
-
  name: '测试引用.env环境变量内的值'
  request:
    method: POST
    url: ${ENV(base_url_test)}/login
    params:
      username: ${ENV(username)}
      password: ${ENV(password)}
  validate:
    - eq: [status_code, 200]
    - eq: [headers."Content-Type", "application/json"]

7、引用其他用例

示例:

config:
  name: '引用其他用例'
  variables: {}
  verify: False

teststeps:
  - name: '引用login接口用例'
  - testcase: testcases/login.yaml       #引用login用例:login用例存放的路径

  - name: '引用login接口用例'
    request:
    method: POST
    url: ${ENV(base_url_test)}/getList
    headers:
    	Accept: application/json, text/plain, */*
        Accept-Encoding: gzip, deflate, br
        Accept-Language: zh-CN,zh;q=0.9
        Connection: keep-alive
        Host: 127.0.0.1:8080
    validate:
    - eq: [status_code, 200]
    - eq: [headers."Content-Type", "application/json"]

8、上传文件

upload文件上传:需要2个依赖包(requests_toolbelt 、 filetype

pip install requests_toolbelt
pip install filetype
pip install  requests_toolbelt filetype  #两个依赖包一起下载

示例:

config:
  name: '上传文件'
  variables: {}
  verify: False

teststeps:

  - name: '上传文件upload file'
    request:
    method: POST
    url: ${ENV(base_url_test)}/upload
    upload:
    file: data/test_photo.png      #文件路径
    title: "上传图片"
    validate:
    - eq: [status_code, 200]
    - eq: [headers."Content-Type", "application/json"]

五、测试报告

1、原生测试报告

V4.3.5版本自带原生的html测试报告,可通过 hrp run -h 得知:hrp run <用例> -g
(不管在那个目录下运行,同一根目录会生成results文件件)
查看生成报告的命令:hrp run -h
在这里插入图片描述
执行命令:

hrp run <测试用例> -g

在这里插入图片描述
使用浏览器打开report.html
在这里插入图片描述
以上报告不美观,信息不完整,难以一眼看出执行情况。

pytest同时也自带html报告,执行一下命令生成pytest的测试报告:

pytest -html=results/results.html  # 等号后面为报告存放的路径

如下图pytest报告,也不美观,无统计。
在这里插入图片描述

2、Allure测试报告

在这里插入图片描述
在这里插入图片描述
Allure报告美观大气,一眼看出执行情况及返回报文均为json格式。

2.1、下载Allure

  1. 下载安装Allure
  2. 配置环境变量(参考Windows&Mac);
  3. 验证环境变量是否配置成功: allure --version 显示版本信息则配置成功;
    在这里插入图片描述
  4. 在Python中下载allure-pytest插件:pip install allure-pytest ;
    在这里插入图片描述

3、Allure的使用

  • 执行用例并生成报告:
pytest  <用例> -s -q  --alluredir  ./results  --clean-alluredir   ##存放路径,--clean-alluredir清空历史数据

运行后可以看到生成了txt,json等格式的文件,还未生成HTML格式:
在这里插入图片描述
接着执行:

allure generate report/ -o results/html  --clean  

执行后,生成html文件下的index.html
在这里插入图片描述
在这里插入图片描述

打开index.html文件如下图:
在这里插入图片描述

六、其他(敬请期待)

1、将测试报告发送邮件及发送到群聊-Done

在这里插入图片描述

在这里插入图片描述

2、Httprunner4.3.5+Locust+Grafana实现性能监控-ing

在这里插入图片描述

希望上文对您有所帮助,遇到问题欢迎留言,有空都会回复的,谢谢大家!

创作不易,你的鼓励将是我创作的最大动力。。。

  • 18
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dreams°123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值