JSON-based interface test framework

Learn more information, please add QQ group: 822 601 020 acquisition

Achieve results
Single Interface / assertion

Multiple interface / dependence the Session / intermediate variables

Demand scenario:

  1. The company Micro service interfaces using a digital signature, using Postman debugging interface every time you need to modify the source code to verify sign temporarily closed, but after closing, other micro service can not invoke the normal service
  2. ELK crawl from the interface to the parameters, need Json format, I usually use Sublime Text + PrettyJson plug, use Postman debugging, some form class interface, also you need to copy the value of each parameter and out, particularly troublesome.

The principle:

  • Sublime text3 can customize the build system
  • Convenient Python json data processing
  • A Python Signature Algorithm
  • request requests transmission interface

Goals:

  • Json file using the data driver, comprising a plurality of interfaces supporting a json
  • Support GET / POST / DELETE / ... method
  • Support form class / Json request class
  • 支持headers, cookies, params, data, files, timeout
  • Support session dependence, intermediate variables

Data file format:

  • Get request
{
  "url": "http://127.0.0.1:5000/api/user/logout/?name=张三"
}

or

{
  "url": "http://127.0.0.1:5000/api/user/logout/",
  "params": {"name": "张三"}
}
  • Post request form:
{
  "url": "http://127.0.0.1:5000/api/user/login/",
  "data": {"name": "张三","password": "123456"}
}
  • Json format of the request:
{
  "url": "http://127.0.0.1:5000/api/user/reg/",
  "headers": {"Content-Type": "application/json"},
  "data": { "name": "张991", "password": "123456"}
}

or

{
  "url": "http://127.0.0.1:5000/api/user/reg/",
  "type": "json",
  "data": { "name": "张991","password": "123456"}
}
  • Format assertion (ASSERT):
{
  "url": "http://127.0.0.1:5000/api/user/login/",
  "data": {"name": "张三","password": "123456"},
  "ASSERT": ["response.status_code == 200", "'成功' in response.text"]
}
  • Require a signature (SIGN):
{   "url": "http://127.0.0.1:5000/api/user/delUser/",
    "type": "json",
    "data": {"name": "张三"},
    "SIGN": true
}
  • Multi-interface, session-dependent, and the intermediate variables (the STORE)
[
    {
        "url": "http://127.0.0.1:5000/api/user/getToken/",
        "method": "get",
        "params": {"appid": "136425"},
        "STORE": {"token": "response.text.split('=')[1]"}
    },
    {   "url": "http://127.0.0.1:5000/api/user/updateUser/?token=%(token)s",
        "headers": {"Content-Type": "application/json"},
        "data": {"name": "张三","password": "123456"}
    }
]

Tool to achieve:

sign.py

import hashlib

appid = user
appsecret = NTA3ZTU2ZWM5ZmVkYTVmMDBkMDM3YTBi

def md5(str):
    m = hashlib.md5()
    m.update(str.encode('utf8'))
    return m.hexdigest()  #返回摘要,作为十六进制数据字符串值


def makeSign(params):
    if not isinstance(params, dict):
        print("参数格式不正确,必须为字典格式")
        return None
    if 'sign' in params:
        params.pop('sign')
    sign = ''
    for key in sorted(params.keys()):
        sign = sign + key + '=' + str(params[key]) + '&'
    sign = md5(sign + 'appsecret=' + appsecret)
    params['sign'] = sign
    return params

post_json.py

import json
import os
import requests
from sign import makeSign

timeout = 10


def postJson(path, timeout=60):
    try:
        with open(path, encoding='utf-8') as f:
            apis = json.load(f)
    except IOError as e:
        print(e)

    except json.decoder.JSONDecodeError:
        print("json文件格式有误")
        
    if isinstance(apis, dict):
        apis=[apis]

    session = requests.session()
    for api in apis:

        # 处理全局变量
        str_api = json.dumps(api)
        if '%' in str_api:
            api = json.loads(str_api % globals())

        # 获取接口相关项
        url = api.get('url')
        method = api.get('method')
        type = api.get('type')
        headers = api.get('headers')
        cookies = api.get('cookies')
        params = api.get('params')
        data = api.get('data')
        files = api.get('files')

        # 特定动作(系统标签)
        _sign = api.get('SIGN')  # 对数据进行签名
        _store = api.get('STORE') # 存储变量
        _assert = api.get('ASSERT') # 结果断言
        
        # 处理签名
        if _sign:
            data = makeSign(data)

        # 如果json请求,转换一下数据
        if type and type == 'json' or headers and 'json' in json.dumps(headers):
            data = json.dumps(data)

        # 根据method发送不同请求
        if not method or method.lower() == 'post': # 有data字段默认使用post方法
            response = session.post(url=url, headers=headers, cookies=cookies, params=params, data=data, files=files, timeout=timeout)  
        elif not data or method.lower() == 'get': # 没有data字段默认采用get方法
              response = session.get(url=url, headers=headers, cookies=cookies, params=params, timeout=timeout)
        elif method.lower() == 'delete':
            response = session.delete(url=url, headers=headers, cookies=cookies, params=params, data=data, files=files, timeout=timeout)
        elif method.lower() == 'put':
            response = session.put(url=url, headers=headers, cookies=cookies, params=params, data=data, files=files, timeout=timeout)
        elif method.lower() == 'patch':
            response = session.patch(url=url, headers=headers, cookies=cookies, params=params, data=data, files=files, timeout=timeout)
        elif method.lower() == 'head':
            response = session.head(url=url, headers=headers, cookies=cookies, params=params, data=data, files=files, timeout=timeout)
        else:
            print("不支持当前方法")
        
        # 存储中间结果
        if _store:
            for key in _store:
                globals()[key]=eval(_store[key])
        
        # 处理响应
        try:
            response_text = json.dumps(response.json(), ensure_ascii=False, indent=2)
        except json.decoder.JSONDecodeError:  # only python3
            try:
                response_text = response.text
            except UnicodeEncodeError:
                # print(response.content.decode("utf-8","ignore").replace('\xa9', ''))
                response_text = response.content
        finally:
            pass

        # 处理断言
        status = "PASS"
        if _assert:
            assert_results = []
            for item in _assert:
                try:
                    assert eval(item)
                    assert_results.append("PASS: <%s>" % item)
                except AssertionError:
                    assert_results.append("FAIL: <%s>" % item)
                    status = "FAIL"
                except Exception as e:
                    assert_results.append("ERROR: <%s>\n%s" % (item, repr(e)))
                    status = "ERROR"
        
        # 打印结果
        print("="*80)
        print("请求:")
        print("Url: %s\nHeaders: %s\nData: %s" % (url, headers, data if isinstance(data, str) else json.dumps(data)))
        print("-"*80)
        print("响应:")
        print(response_text)
        if _assert:
            print("-"*80)
            print("断言:")
            for assert_result in assert_results:
                print(assert_result)

def main():
    if len(sys.argv) != 2:
        print("缺少参数:json文件")
    else:
        postJson(sys.argv[1])

main()

Integrated into the Sublime

  1. Sublime Text3 -> Tools -> Build System -> New Build System
    Copy the following code, modify your Python3 environment for the Python script path for your post_json.py path, save for the PostJson.sublimet-build
  • Windows System
{
    "cmd": ["python3","C:/PostJson/post_json.py","$file"],
    "file_regex": "^[ ] *File \"(...*?)\", line ([0-9]*)",
    "selector": "source.json",
    "encoding":"cp936",
}
  • Linux & Mac
{
    "cmd": ["/Library/Frameworks/Python.framework/Versions/3.6/bin/python3","-u","/Users/apple/Applications/PostJson/post_json.py","$file"],
    "file_regex": "^[ ] *File \"(...*?)\", line ([0-9]*)",
    "selector": "source.json",
    "env": {"PYTHONIOENCODING": "utf8"}, 
}

Instructions

PrettyJson recommended to install plug-ins

  1. In Sublime text3, the new json file, and save it as * .json
{
  "url": "http://127.0.0.1:5000/api/user/login/",
  "data": {"name": "张三","password": "123456"}
}
  1. Press Ctrl + B run

Project Path

Github: PostJson

It complements the following features:

  • Use cases discover, automatic discovery and batch execution
  • Generate reports
  • Command line parameters
    • verbose: display levels: 1. Display only Example 2. The results show only the response text (default) The display request, and in response to the assertion information
    • host: specify the server address
    • env: Specifies the environment
    • timeout: 指定timeout
    • html: html report specify the output path
    • log: log output path Specifies
    • collect-only: list only all use cases

All

  • Complete test report
  • Support Database Comparison
  • Support the implementation of Sql, Shell, Cmd commands
  • Use coroutine, asynchronous concurrent
  • Support for distributed execution
  • Support for regular execution
  • Continuous integration

Guess you like

Origin www.cnblogs.com/superhin/p/11455230.html