Testtp --- http client for testers

Apache-2.0 License
Python
Be5yond · December 10, 2020 · 2536 次阅读 · 0 条评论

Supported Features


数据动态渲染


变量缓存---cache

“{{ x }}"字符串括起来的数据 x 被认为是变量,运行时将替换成 cache 中的对应数据。

s = Session()
s.cache = {'token_holder': 'real_token'}  # 设置缓存数据
body={'data': 'testdata', 'token': '{{ token_holder }}'}
s.post('http://httpbin.org/post', json=body)
>>> OUTPUT
2020-12-06 22:07:40.964 | SEND     | testtp.Req:_wrapper:35 - <= request body => 
{
    "data": "testdata",
    "token": "real_token"  # token被替换成cache中的数据
}

上下文数据缓存---stash

Session 将最近一次请求的 response 存储。使用 stash 函数可以从 response 数据抽取关键的数据,存储到 cache,供后面请求使用,
json_query 提取规则为jmespath规则

s = Session()
s.cache = {'token_holder': 'real_token'}
body={'data': 'testdata', 'token': '{{ token_holder }}'}
s.post('http://httpbin.org/post', json=body)
s.stash(json_query='headers.Host', key='host') # 将返回的content中 'header.Host'字段存到缓存cache中,key为'host'
print(self.cache)

>>> OUTPUT
{"token_holder": "real_token", "host": "httpbin.org"}

body={'context_vars': '{{ host }}'}
s.post('http://httpbin.org/post', json=body)

>>> OUTPUT
2020-12-06 22:07:41.644 | SEND xx   | testtp.Req:_wrapper:35 - <= request body => 
{
    "context_vars": "httpbin.org"
}

使用函数实时计算参数---register_render

“{% f(x) %}"字符串括起来的数据 f(x) 被认为是函数,运行时将执行函数来生成数据。

支持 python 内置函数例如 random.randint(), 也可以用 register_render 将自定义函数注册给渲染器使用。

def get_timestamp(shift: int):
        return int(time.time()) + shift
s = Session()
s.register_render(get_timestamp) 
body={'data': 'testdata', 'timestamp': '{% get_timestamp(100) %}'}
s.post('http://httpbin.org/post', json=body)

>>> OUTPUT
2020-12-06 22:36:32.784 | SEND     | testtp.Req:_wrapper:35 - <= request body => 
{
    "data": "testdata",
    "timestamp": 1607265492  # 实际参数为get_timestamp函数返回的当前时间戳
}

数据校验


校验返回 body---validate

validate 方法对 response 进行格式校验, scm 与请求数据一样会经过 render 处理,支持变量和函数规则同"{{ x }}", "{% f %}".

*注意schema中的函数只传函数名,执行时会将 response 对应位置的值作为参数调用 f,函数 f 的返回,应是一个 bool 值。

def is_url(s):
    return s.startswith('http')
s = Session()
s.get('http://httpbin.org/get')
scm = {
    "args": {},
    "headers": {
        "Accept": "{% str %}",
        "Accept-Encoding": "{% str %}",
        "Host": "httpbin.org",
        "User-Agent": "{% str %}",
        "X-Amzn-Trace-Id": "{% str %}"
    },
    "origin": "{% str %}",
    "url": "http://httpbin.org/get"
}
s.validate(scm)

>> OUTPUT
2020-12-07 14:40:05.689 | SEND     | testtp.Req:_restore_resp:22 - <= request url => 
http://httpbin.org/get
2020-12-07 14:40:05.691 | RECV     | testtp.Req:_restore_resp:23 - <= response data => 
{
    "args": {},
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Host": "httpbin.org",
        "User-Agent": "python-requests/2.25.0",
        "X-Amzn-Trace-Id": "Root=1-5fcdce45-6e7808ba224497484deb1bf1"
    },
    "origin": "223.223.188.146",
    "url": "http://httpbin.org/get"
}
2020-12-07 14:40:05.695 | DEBUG    | testtp.Req:validate:81 - <= schema template => 
{'args': {}, 'headers': {'Accept': <class 'str'>, 'Accept-Encoding': <class 'str'>, 'Host': 'httpbin.org', 'User-Agent': <class 'str'>, 'X-Amzn-Trace-Id': <class 'str'>}, 'origin': <class 
'str'>, 'url': <function test_validate_response_custom_function.<locals>.is_url at 0x000001B478983280>}

数据抽取---json_query

有些场景下需要对返回数据进行一些预处理(如:抽取关键字段,求和,求最大值等),之后才进行校验,这时需要传入数据处理规则 json_query,提取规则为jmespath规则

data = {
    'data_list': [
        {'type': 'A', 'count': 80},
        {'type': 'B', 'count': 90},
        {'type': 'C', 'count': 70},
        {'type': 'D', 'count': 50},
        ]
    }
url = 'http://httpbin.org/post'
s = Session()
s.post(url, json=data)
scm = ['A', 'B', 'C', 'D']
s.validate(schema=scm, json_query='json.data_list[].type')

>> OUTPUT
2020-12-07 14:38:31.241 | RECV     | testtp.Req:_restore_resp:23 - <= response data => 
{
    "args": {},
    "data": "{\"data_list\": [{\"type\": \"A\", \"count\": 80}, {\"type\": \"B\", \"count\": 80}, {\"type\": \"C\", \"count\": 80}, {\"type\": \"D\", \"count\": 80}]}",
    "files": {},
    "form": {},
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Content-Length": "127",
        "Content-Type": "application/json",
        "Host": "httpbin.org",
        "User-Agent": "python-requests/2.25.0",
        "X-Amzn-Trace-Id": "Root=1-5fcdcde7-332bb4ee193f31915faee06b"
    },
    "json": {
        "data_list": [
            {"count": 80,"type": "A"},
            {"count": 90,"type": "B"},
            {"count": 70,"type": "C"},
            {"count": 50,"type": "D"},
        ]
    },
    "origin": "223.223.188.146",
    "url": "http://httpbin.org/post"
}
2020-12-07 14:38:31.246 | DEBUG    | testtp.Req:validate:73 - <= json query => 
json.data_list[].type
2020-12-07 14:38:31.247 | DEBUG    | testtp.Req:validate:74 - <= extract body => 
['A', 'B', 'C', 'D']
2020-12-07 14:38:31.248 | DEBUG    | testtp.Req:validate:81 - <= schema template => 
['A', 'B', 'C', 'D']
评论列表
No Comment at the moment.