HttpTesting

Apache License 2.0
python
windows,mac,linux
天枢 · 2020年03月18日 · 2622 次阅读 · 0 条评论

HttpTesting

Build StatusPyPIPyPI - LicensePyPI - Python VersionPyPI - Wheel

HttpTesting 是 HTTP(S) 协议接口测试框架,通过 YAML 来编写测试用例,通过命令行运行代码,不固定目录结构,支持通过命令行生成脚手架。

功能描述

httptesting 通过 YAML 编写测试用例,安装 httptesting 后通过 amt 命令执行测试用例,支持指定 YAML 中 CASE 名称进行单用例执行,支持指定请求头默认值来共享请求头,支持自定义扩展功能 (在 case 执行根目录下创建 extfunc.py 文件来自定义代码)。
支持多进程执行用例,支持用例执行出错重试功能,支持设定执行用例次数;支持设置控制台输出和报告输出;支持参数化功能与用户自定义用户变量。

安装包下载:

https://pypi.org/project/httptesting/#files

源码:

https://github.com/HttpTesting/pyhttp

版本信息

序号 版本号 描述
1 v1.0 使用 unittest 框架
2 v1.1 使用 pytest 框架

快速开始

环境准备

python 虚拟环境 virtualenv 使用

  • 安装虚拟环境: pip install virtualenv

  • 创建虚拟环境: virtualenv demo_env

  • 命令行模式切换到虚拟环境 Script 目录: /../scripts/

  • 激活虚拟环境: activate.bat

HttpTesting 安装

以下三种方式选择其一即可。

pip 在线安装
  • pip install HttpTesting==1.1.69
下载 whl 文件进行安装
  • pip install HttpTesting-1.1.69-py3-none-any.whl
更新 httptesting 包

已安装 httptesting 包,通过 pip 命令进行更新

  • pip list 查看 HttpTesting 安装包版本信息

  • pip install --upgrade HttpTesting

  • pip install --upgrade HttpTesting==1.0.26

使用命令运行

以下四个命令作用相同

  • am
  • AM
  • amt
  • AMT
序号 命令参数 描述
1 am -conf set 或--config set 此命令用来设置 config.yaml 基本配置
2 am -f template.yaml 或--file template.yaml 执行 YAML 用例,支持绝对或相对路径
3 am -d testcase 或--dir testcase 批量执行 testcase 目录下的 YAML 用例,支持绝对路径或相对路径
4 am -sp demo 或--startproject demo 生成脚手架 demo 目录,以及用例模版
5 am -har httphar.har 根据抓包工具导出的 http har 文件,生成测试用例 YAML
6 am -c demo.yaml 或--convert demo.yaml 转换数据为 HttpTesting 测试用例

基本配置

  • [通过开关启用功能:并发执行, 失败重新执行, 用例执行次数, Debug 模式,输出模式 (html 与控制台),URL 基本路径]

  • URL 设置

  • 钉钉机器人设置

  • 测试报告设置

  • EMAIL 邮箱设置

  • 用例执行配置

用例执行

  • YAML 执行:

  • [整个 YAML 文件执行,指定 CASE 名称执行,批定多个 CASE 名称执行并且按指定顺序执行]

  • am -f template.yaml

  • am -f template.yaml Case1

  • am -f template.yaml Case2 Case1

  • YAML 批量执行:

  • [批量执行 testcase 目录下所有 YAML 测试用例文件]

  • am -dir testcase

脚手架生成

  • am -sp demo 此命令生成一个 demo 文件夹结构。

  • 脚手架功能,是生成一个测试用例结构与 Case 模版.

HAR

  • 执行命令: am -har httphar.har 自动生成 httptesting 用例 har_testcase.yaml。

  • har 命令来解析, Charles 抓包工具导出的 http .har 请求文件, 自动生成 HttpTesting 用例格式.

用例编写

用例模型

TESTCASE{

'case1':['description',{},{}], # 场景模式每个{}一个接口

'case2':['description',{}], # 单接口模式

}

YAML 用例格式

场景模式

TESTCASE:
    #Case1由两个请求组成的场景
    Case1:
        -
            Desc: xxxx业务场景(登录->编辑)
        -
            Desc: 登录接口
            Url: /login/login
            Method: GET
            Headers:
                content-type: "application/json"
                cache-control: "no-cache"
            Data:
                name: "test"
                pass: "test123"
            OutPara: 
                "H_token": result.data
                "content_type": header.content-type
                "name": Data.name 
                "pass": Data.pass
            Assert:
                - eq: [result.status, 'success']
        -
            Desc: 编辑接口
            Url: /user/edit
            Method: GET
            Headers:
                content-type: "${content_type}$"   
                cache-control: "no-cache"
                token: "$H_token$"
            Data:
                name: "${name}$"
                pass: "${pass}$"
            OutPara: 
                "$H_token$": result.data
            Assert:
                - ai: ['success', result.status]
                - eq: ['result.status', '修改成功']

多 CASE 模式

TESTCASE:
    #同一接口,不同参数,扩充为多个CASE
    Case1:
        -
            Desc: 登录接口-正常登录功能
        -
            Desc: 登录接口
            Url: /login/login
            Method: GET
            Headers:
                content-type: "application/json"
                cache-control: "no-cache"
            Data:
                name: "test"
                pass: "test123"
            OutPara: 
                "H_cookie": cookie.SESSION
            Assert:
                - eq: [result.status, 'success']
    Case2:
        -
            Desc: 登录接口-错误密码
        -
            Desc: 登录接口
            Url: /login/login
            Method: GET
            Headers:
                content-type: "application/json"
                cache-control: "no-cache"
            Data:
                name: "test"
                pass: "test123"
            OutPara:
                "H_cookie": cookie.SESSION 
            Assert:
                - eq: [result.status, 'error']

参数说明

  • "${H_cookie}$": 为参数变量,可以头信息里与 Data 数据里进行使用
  • "%{md5('aaaa')}%": 为函数原型,具体支持函数下方表格可见.

自定义变量

变量作用域为当前 CASE.

  • 通过在 Case 下定义 USER_VAR 字段,来自定义变量
  • USER_VAR 字段下定义的字段为用户变量,作用于当前 Case

示例 1(自定义变量)

TESTCASE: 
    Case1:
        - 
            Desc: 接口详细描述
            USER_VAR:
                token:  xxxxxxxx
        -
            Url: /xxxx/xxxx
            Method: POST
            Headers: 
                token: ${token}$
            Data:
            OutPara:
            Assert: []

示例 2(自定义变量)

TEST_CASE:
    Case1:
    -   
        Desc: 扫码校验券(支持检测微信券二维码码、微信会员h5券二维码、条码)
        USER_VAR:
            version: 1.0
            data: 
                req:
                    sid: '1380598237'
                    wxcode: "164073966187485312752286" #209736174428
                appid: dp0Rm4wNl6A7q6w1QzcZQstr
                sig: 9c8c96b38d759abe6633c124a5d37225
                v: "${version}$"
                ts: 1564643536

    -   Desc: 扫码校验券
        Url: /pos/checkcoupon
        Method: POST
        Headers:
            content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
            cache-control: no-cache
        Data: ${data}$
        OutPara: 
        Assert:
        -   eq: [result.errcode, 0]
  • 以上通过 USER_VAR 字典对象来定义变量, key 为变量名, value 为变量值; 使用方法: ${token}$

  • 无需定义变量, USER_VAR 字段在用例中,可以省略.

OutPara 字段变量使用

OutPara 字段用来做公共变量,供其它接口使用,默认为"";

  • 示例: "H_token": result.data 是请求结果,返回的嵌套级别,使用方法: ${H_token}$
  • OutPara 为 dict 类型,可以做多个公共变量.

Assert 断言

Assert 字段默认为 [].

序号 断言方法 断言描述
1 eq: [a, b] 判断 a 与 b 相等,否则 fail
2 nq: [a, b] 判断 a 与 b 不相等,否则 fail
3 al: [a, b] 判断 a is b 相当于 id(a) == id(b),否则 fail
4 at: [a, b] 判断 a is not b 相当于 id(a) != id(b)
5 ai: [a, b] 判断 a in b ,否则 fail
6 ani: [a, b] 判断 a in not b,否则 fail
7 ais: [a, b] 判断 isinstance(a, b) True
8 anis: [a, b] 判断 isinstance(a, b) False
9 ln: [a] 判断 a is None,否则 fail
10 lnn: [a] 判断 a is not none
11 bt: [a] 判断 a 为 True
12 bf: [a] 判断 a 为 False

内置函数及扩展

使用原型 (带参数与不带参数)

  • "%{md5('aaaa')}%" 或 "%{timestamp()}%"
函数名 参数 说明
md5 txt 字符串 生成 md5 字符串示例: cbfbf4ea6d7c8032584dcf0defa10276
timestamp - 秒级时间戳示例: 1563183829
uuid1 - 生成唯一 id,uuid1 示例:ebcd6df8a77611e99bb588b111064583
datetimestr - 生成日期时间串,示例:2019-07-16 10:50:16
mstimestamp - 毫秒级时间戳,20 位
sleep_time - 线程睡眠,0.5 为 500 毫秒,1 为 1 秒
rnd_list [] 随机从列表中选择值
  • 其它后续添加

自定义函数扩展功能说明

  • 在执行用例 root 目录,新建 extfunc.py 文件
  • 按模型自定义函数
  • 类名 Extend 不可更改
  • @staticmethod函数必须定义为静态
  • 函数各数不做限制

自定义函数扩展功能模型

class Extend:
    @staticmethod
    def func1():
        return 'ext func'

    @staticmethod
    def func2(args):
        return args
  • 使用示例 1:"%{func1()}%"
  • 使用示例 2: "%{func1('aaaa')}%"

参数化功能

定义参数化参数后,同一用例会按照参数个数决定用例执行次数。

  • 通过在用例 Case 下定义 PARAM_VAR 字段
  • PARAM_VAR 字段下定义参数化变量,供之后引用
  • 如果在 PARAM_VAR 下定义多个,参数化变量,参数个数要匹配。
  • 现在如果定义了多个参数化变量,执行用例的次数是排列组合数。
  • 之后如有必要会改成,按参数化变量内参数的各数决定执行用例次数。

参数化功能模型

TEST_CASE:
    Case2:
    -   Desc: 给指定用户发送验证码
        USER_VAR:
            cno_list:
            - '1674921314241197'
            - '1581199496593872'
            - '1623770534820512'
            - '1674921701066628'
            - '1581199096195979'
            - '1623770606653991'
        PARAM_VAR: 
            sig: ["1", "2", "3", "4"]
            rem: ["4", "5", "6", "7"]

    -   Desc: 给指定用户发送验证码
        Url: /user/sendcode
        Method: POST
        Headers:
            content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
            cache-control: no-cache
        Data:
            req:
                cno: '%{rnd_list("${cno_list}$")}%'
            appid: dp1svA1gkNt8cQMkoIv7HmD1
            sig: "${sig}$"
            v: 2.0
            ts: 123
        OutPara: null
        Assert:
        -   eq:
            - result.errcode
            - 0
        -   eq:
            - result.res.result
            - SUCCESS
  • 需要注意事项:
  • PARAM_VAR: 下可以有多个参数化变量,必须是 key value 键值对,并且 value 必须是 list 类型
  • PARAM_VAR:下有多个参数时,value 各数必须相等。
  • 以上例子中为倒,生成的参数是 ${sig}$ , ${rem}$ 对应的值为 ["1", "4"] ,["2", "5"],["3", "6"] ,["4", "7"]
  • value 各数决定了参数化的 case 行数。
  • 上例会生成 4 个参数组合,也就是生成 4 条 case。

常用对象 (通常做参数变量时使用)

  • res: 请求 Response 对象
  • result: res.json 或 res.text
  • cookie: res.cookie 响应 cookie 字典对象; 当做为参数时如果 cookie.SESSION 这样的写法代表取 cookie 中的 SESSION 对象. 如果只写 cookie,会解析成"SESSION=xxxxxxx; NAME=xxxxxx"
  • headers: res.headers 响应头字典对象
  • header: header.content-type 请求头对象

用例执行

  • 1、生成脚手架
  • 2、编写脚手架中 testcase 下 YAML 模版用例
  • 3、切换到 testcase 目录
  • 4、amt -dir testcase 自动运行 testcase 下 YAML 用例
  • 5、自动生成测试报告 Html

框架基本配置

  • 1、通过命令打开框架 config.yaml
  • 2、amt -conf set ; amt -conf get
  • amt -conf set => all
  • am -conf set BASE_URL=http://api.xxx.net
  • am -conf get BASE_URL => http://api.xxx.net
  • 3、修改基本配置,并保存

新增功能

指定 case 编号执行

  • 指定单个 Case 执行 amt -f xxxx.yaml Case1
  • 指定多个 Case 执行 amt -f xxxx.yaml Case1 Case2 Case3

智能 URL

当用例中指定全路径时,自去取该路径,当不是绝对路径时,取 BASE_URL 进行智能拼接。

请求头默认值

TEST_CASE:
    Case1:
    -   Desc: 给用户发送验证码业务场景(发送1->发送2)
        USER_VAR:
            cno_list:
            - '1674921314241197'
            - '1581199496593872'
            - '1623770534820512'
            - '1674921701066628'
            - '1581199096195979'
            - '1623770606653991'

        REQ_HEADER:
            content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
            cache-control: no-cache            

    -   Desc: 给指定用户发送验证码1
        Url: /user/sendcode
        Method: POST
        Data:
            req:
                cno: '%{rnd_list("${cno_list}$")}%'
            appid: dp1svA1gkNt8cQMkoIv7HmD1
            sig: "123"
            v: 2.0
            ts: 123
        OutPara: null
        Assert:
        -   eq:
            - result.errcode
            - 0
        -   eq:
            - result.res.result
            - SUCCESS
    -   Desc: 给指定用户发送验证码2
        Url: /user/sendcode
        Method: POST
        Data:
            req:
                cno: '%{rnd_list("${cno_list}$")}%'
            appid: dp1svA1gkNt8cQMkoIv7HmD1
            sig: "123"
            v: 2.0
            ts: 123
        Headers:
            content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
            cache-control: no-cache             
        OutPara: null
        Assert:
        -   eq:
            - result.errcode
            - 0
        -   eq:
            - result.res.result
            - SUCCESS
  • 在 Case 中增加 REQ_HEADER 字段来做为公共的请求头。
  • 之后 Case 中执行共享此请求头
  • 如果在用例中设置了 REQ_HEADER 字段与请求中也单独设置了请求头,那么第一顺序为请求中的为主。
  • 上边的例子为场景用例,由两个请求组成,请求 1,使用的是请求头默认值,请求 2,使用自身请求头。

Case 执行顺序

TEST_CASE:
    Case1:
    -   
        Desc: 给用户发送验证码业务场景(发送1->发送2)
        Order: 10
        USER_VAR:
            cno_list:
            - '1674921314241197'
            - '1581199496593872'
            - '1623770534820512'
            - '1674921701066628'
            - '1581199096195979'
            - '1623770606653991'

        REQ_HEADER:
            content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
            cache-control: no-cache            

    -   Desc: 给指定用户发送验证码1
        Url: /user/sendcode
        Method: POST
        Data:
            req:
                cno: '%{rnd_list("${cno_list}$")}%'
            appid: dp1svA1gkNt8cQMkoIv7HmD1
            sig: "123"
            v: 2.0
            ts: 123
        OutPara: null
        Assert:
        -   eq: [result.errcode, 0]
  • 以上示例 Order 字段为执行 Case 权重,全局根所此字段来排执行顺序。默认为 0,字段可省略。
  • Order 越大,越靠后执行。

CSV 文件参数化

TEST_CASE:
    Case1: #用例1
        -
            Desc: 当日储值统计/charge/today
            USER_VAR:
                appkey: '0100ff174e808de80db21152ca7dde31'
            PARAM_VAR:
                sig: ["1", "2"]
                rem: ["4", "5"]
            CSV_VAR: 
                file_path: 'd:/deal.csv'
            Order: 20
        -
            Desc: 当日储值统计
            Url: /charge/today
            Method: POST
            Headers:
                content-type: "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"
                cache-control: "no-cache"
            Data: 
                req: 
                    begin_time: "${name}$"
                    end_time: "${age}$"
                    shop_id: 1512995661
                appid: 'aaaaa'
                sig: "%{sign({'data': 'data.req', 'appid':'data.appid', 'ts':'data.ts', 'v': 'data.v','appkey':'${appkey}$'})}%"
                v: 2.0
                ts: 1564967996
            OutPara: 
            Assert:
                - eq: [result.errcode, 1006]
  • 在用例结果头部增加 CSV_VAR 字典对象,并指定 file_path key 值,为 xxxx.csv 文件路径
  • 如果用例头部存在 CSV_VAR 说明启用 CSV 参数化。
  • 参数化使用时 CSV 列名,即为引用字段名,引用方法"${字段名}$.
  • 参数化需注意,CSV 每一行为一个 CASE。
  • PARAM_VAR 也为参数化功能,当与 CSV_VAR 同时存在时,以 CSV 为准

Case 跳过

TEST_CASE:
    Case1: #用例1
        -
            Desc: 会员标记编辑->获取
            USER_VAR:
                appkey: '4b6ef4ee839dfb0922c28e97143d371e'
            Skip: True
        -
            Desc: 第三方收银会员标记-编辑接口
            Url: /userremark/edit
            Method: POST
            Headers:
                content-type: "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"
                cache-control: "no-cache"
            Data: 
                req: 
                    uid: "384345911306964992"
                    token: "adc97617d8c42cd1c99211cab81a2a80"
                    remark: "123456"
                appid: "dp3wY4YtycajNEz23zZpb5Jl"
                sig: "%{sign({'data': 'data.req', 'appid':'data.appid', 'ts':'data.ts', 'v': 'data.v','appkey':'${appkey}$'})}%"
                v: 2.0
                ts: 1564967996
            OutPara: 
                token: data.req.token
                remark: data.req.remark
                uid: data.req.uid
            Assert:
                - eq: [result.errcode, 0]
                - eq: [result.res, ""]
  • 在用例头部分,增加 Skip: True 标记该 case 跳过
  • Skip: False 或 Skip 字段不存在则不会跳过用例执行

  • 从以下用例中可以看出,第二个接口中多了一个 Skip: True 字段,这样执行时,就会跳过该接口,只执行第一个接口。

  • skip 支持自定义函数:Skip: "%{skip_func()}%"; 但是返回参数必须是 True 或 'True'才能跳过。

    场景中单接口跳过

    TEST_CASE:
        Case1: 
            -
                Desc: 当日储值统计/charge/today
                USER_VAR:
                    appkey: '0100ff174e808de80db21152ca7dde31'
                # CSV_VAR: 
                #     file_path: 'd:/deal.csv'
                Order: 20
            -
                Desc: 当日储值统计1
                Url: /charge/today
                Method: POST
                Headers:
                    content-type: "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"
                    cache-control: "no-cache"
                Data: 
                    req: 
                        begin_time: "aaaa"
                        end_time: "bbbb"
                        shop_id: 1512995661
                    appid: 'aaaaa'
                    sig: "%{sign({'data': 'data.req', 'appid':'data.appid', 'ts':'data.ts', 'v': 'data.v','appkey':'${appkey}$'})}%"
                    v: 2.0
                    ts: 1564967996
                OutPara: 
                Assert:
                    - eq: [result.errcode, 1006]
            -
                Desc: 当日储值统计2
                Skip: True
                Url: /charge/today2
                Method: POST
                Headers:
                    content-type: "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"
                    cache-control: "no-cache"
                Data: 
                    req: 
                        begin_time: "aaaa"
                        end_time: "dddd"
                        shop_id: 1512995661
                    appid: 'aaaaa'
                    sig: "%{sign({'data': 'data.req', 'appid':'data.appid', 'ts':'data.ts', 'v': 'data.v','appkey':'${appkey}$'})}%"
                    v: 2.0
                    ts: 1564967996
                OutPara: 
                Assert:
                    - eq: [result.errcode, 1006]
    

功能对比

序号 功能 V1.0 V1.1 配置参数
1 并发执行 - ENABLE_EXECUTION:False EXECUTION_NUM: 4
2 失败重新执行 ENABLE_RERUN: False RERUN_NUM: 2
3 重复执行 - ENABLE_REPEAT: False REPEAT_NUM: 2
4 钉钉消息 ENABLE_DDING: False
5 发送报告邮件 EMAIL_ENABLE: False
6 控制台输出 - ENABLE_EXEC_MODE: False
7 自定义函数扩展 用例执行 root 目录增加 extfunc.py
8 自定义变量 在用例中用 USER_VAR 字段定义变量,作用于当前 Case
9 用例参数化 在用例中用 PARAM_VAR 字段定义参数化变量,作用于当前 Case
10 请求头默认值 设置用例请求头默认值,整个 case 共享请求头。
11 指定 case 执行 - 单个 yaml 文件指定 case 执行
12 Case 执行顺序 - 通过 Order 字段设置 Case 执行优先级
13 Csv 参数化 - 通过外部 csv 文件进行参数化
14 case 跳过 - 通过在 case 中增加标记 Skip: True
15 场景中单接口跳过 - 通过在 case 中增加标记 Skip: True
评论列表
暂无评论.