• 自定义实现httprunner debugtalk 的函数助手功能


    1.需求背景:

    我们在进行接口请求时需要用到各种各样的数据格式,比如随机唯一值,时间戳等等这些可以通过参数化函数来实现httprunner在实现上也参考了jm的类似思想设计 :

    我们如果做平台化时,就可以实现类似debugtalk的设计思路来实现参数化函数自定义使用:

    设计思路:

    1.动态加载模块debugtalk里的方法并且获取参数和返回值:

    2.请求参数提取出函数并且判断它是否在debugtalk加载出来对象方法里,如果在就执行替换方法位里面方法执行返回值:

    第一步,编写debugtalk 定义函数钩子

     第二步:编写动态加载提取方法mapping:

    import types
    import importlib
    import ast
    import re
    import json
    import os
    
    def parse_string_value(str_value):
        """
        :param str_value: '123'==>123
        :return:
        """
        try:
            return ast.literal_eval(str_value)
    
        except ValueError:
            return str_value
        except SyntaxError:
            # e.g. $var, ${func}
            return str_value
    
    
    def load_module_functions(module):
        """
        load debugtalk functions mapping
        """
    
        module_functions = {}
    
        for name, item in vars(module).items():
            if isinstance(item, types.FunctionType):
                module_functions[name] = item
    
        return module_functions
    
    
    def parse_function_params(params):
        """
        parse the function params and return it
        example:
            parse_function_params("1, 2, a=3, b=4")
        :return:  {'args': [1, 2], 'kwargs': {'a':3, 'b':4}}
        """
        function_meta = {
            "args": [],
            "kwargs": {}
        }
    
        params_str = params.strip()
        if params_str == "":
            return function_meta
    
        args_list = params_str.split(',')
        for arg in args_list:
            arg = arg.strip()
            if '=' in arg:
                key, value = arg.split('=')
                function_meta["kwargs"][key.strip()] = parse_string_value(value.strip())
            else:
                function_meta["args"].append(parse_string_value(arg))
    
        return function_meta
    
    
    
    
    
    def extra_func_name(data: dict):
        """
        extract method name list  of data value
        :return : ['__RandomInt(5,8)}}', '__UUID1()'] ect.
         """
        d = json.dumps(data, separators=(',', ':'))
        funcs = re.findall(r"{{(.*?)}}", d)
        return funcs
    
    
    def hook_replace(data: dict)->dict:
        """
        :function: replace the function with debugtalk function's return result
        :param data: {"name": "${{__RandomInt(5,8)}}", "foo2": "${{__UUID1()}}"}
        :return: dict 
        """
        dump_string = json.dumps(data)
        imported_module = importlib.import_module("mysite.debugtalk")
        mapping = extra_func_name(data)
        for method_name in mapping:
            function_name = re.findall("(.*?)[(]", method_name)[0]
            func_mapping = load_module_functions(imported_module)
            function = func_mapping.get(function_name)
            if function:
                params = re.findall(function.__name__ + "[(](.*?)[)]", method_name)[0]
                args_kwargs = parse_function_params(params)
                args, kwargs = args_kwargs.get("args"), args_kwargs.get("kwargs")
                if not args and not kwargs:
                    res = function()
                    if isinstance(res, (int, float, list)):
                        ret = dump_string.replace('"${{' + method_name + '}}"', json.dumps(res))
                        dump_string = ret
                    else:
                        ret = dump_string.replace('${{' + method_name + '}}', str(res))
                        dump_string = ret
                else:
                    res = function(*args, **kwargs)
    
                    if isinstance(res, (int, float, list)):
                        ret = dump_string.replace('"${{' + method_name + '}}"', json.dumps(res))
                        dump_string = ret
                    else:
                        ret = dump_string.replace('${{' + method_name + '}}', str(res))
                        dump_string = ret
        return json.loads(dump_string)
    

    其中hook_replace 方法func_mapping 打印出来是这样:

    {'__RandomString': <function __RandomString at 0x00000185B901A048>, '__RandomInt': <function __RandomInt at 0x00000185B9114510>,

    可以通过key获取到function:

    而key可以提取data = {"name": "${{__RandomInt(5,8)}}", "foo2": "${{__UUID1()}}"},通过正则提取:

    def extra_func_name(data: dict):
    """
    extract method name list of data value
    :return : ['__RandomInt(5,8)}}', '__UUID1()'] ect.
    """
    d = json.dumps(data, separators=(',', ':'))
    funcs = re.findall(r"{{(.*?)}}", d)
    return funcs
    然后迭代数组mapping,再次提取函数名称function_name,这样就可以通过function_name 为key拿到func_mapping 的对应函数对象,

    接下来就需要获取参数了,入参*args,**kwargs:

    params = re.findall(function.__name__ + "[(](.*?)[)]", method_name)[0]

    把参数解析通过args_kwargs = parse_function_params(params)返回:
    {'args': [1, 2], 'kwargs': {'a':3, 'b':4}} 或者 {}
    由于并不是所有的函数都有入参所以需要判断
    if not args and not kwargs:
    res = function()
    else:
        res = function(*args, **kwargs)

    最后就是替换函数助手为实际返回值了,分str一种情况,int,float list 一种情况,因为有的参数要求请求时就是int类型保持原有数据类型:
    if isinstance(res, (int, float, list)):
    ret = dump_string.replace('"${{' + method_name + '}}"', json.dumps(res))
    dump_string = ret
    else:
    ret = dump_string.replace('${{' + method_name + '}}', str(res))
    dump_string = ret

    最后就是关于动态加载模块知识:

  • 相关阅读:
    virtual box 下安装centos 7
    java多线程通信
    redis 实现发布订阅的功能
    Ubuntu系统下为IDEA创建启动图标
    Windows玩转Docker(二):运行whalesay image
    Windows玩转Docker(一):安装
    yarn安装部署
    Hadoop yarn配置参数
    yarn的初步理解
    使用QJM部署HDFS HA集群
  • 原文地址:https://www.cnblogs.com/SunshineKimi/p/15048900.html
Copyright © 2020-2023  润新知