您现在的位置是:主页 > news > discuz蓝色城市门户论坛网站模板/谷歌排名优化入门教程
discuz蓝色城市门户论坛网站模板/谷歌排名优化入门教程
admin2025/5/13 10:09:06【news】
简介discuz蓝色城市门户论坛网站模板,谷歌排名优化入门教程,社区网站 租用服务器还是只需要购买空间,seo学校关注我,每天分享软件测试技术干货、面试经验,想要领取测试资料、进入软件测试学习交流群的可以直接私信我哦~~我们在使用Python进行自动化测试或者测试脚本开发时,通常会在代码中融入数据驱动设计,以便于降低代码开发、维护成本&a…
关注我,每天分享软件测试技术干货、面试经验,想要领取测试资料、进入软件测试学习交流群的可以直接私信我哦~~
我们在使用Python进行自动化测试或者测试脚本开发时,通常会在代码中融入数据驱动设计,以便于降低代码开发、维护成本,例如我们在进行接口自动化测试时,我们会使用不同的数据(入参数据、期望结果数据),驱动同一条自动化测试用例执行,已验证该接口在不同场景下功能是否正常,通常我们会将这些数据存储在数据库、Yaml、Excel或其他文件中。
在数据驱动的具体实现设计中,我们使用的各数据类型通常都是固定值(静态值),比如固定的字符串、数字、列表、字典等等,来驱动自动化测试用例或者脚本的执行。
但当在需要非固定(动态)进行数据驱动测试时,例如,在进行接口测试时,请求体中存在 “time”(当前时间)属性,每次发送请求时,都需要使用当前时间。那么该如何设计代码实现数据驱动呢 ?
本文,通过Python 解析字符串中变量名、函数名(函数的参数),同时支持加载指定自定义模块,获取模块方法及变量对象,以实现动态加载字符串并将字符串中的变量名、函数名,替换为变量值、函数返回值。
我们可以通过下面示例,更直观地了解一下:
示例
例如,我们加载数据驱动文件(YAML格式 ) ,其中包含 变量名、变量名 、变量名、{函数名($变量名, )} 内容。
# Yaml
SignMap:- TIME: ${now_time()}- PHONE: ${phone($MODULE)}- TERMINALNAME: $TERMINAL_NAME- DESC: 当前时间为:${now_time()} ,联系电话为:${phone($MODULE)}
上述Yaml文件中的变量、函数,我们可以在指定的一个或多个自定义模块中进行设计、开发。如下,我们在 built_in.py 模块中设计了MODULE、TERMINAL_NAME 变量,以及now_time、phone 函数。
#!/usr/bin/env python
# -*- encoding: utf-8 -*-import datetimeMODULE = "2"
TERMINAL_NAME= "alibaba"def now_time():"""Returns:"""curr_time = datetime.datetime.now()return curr_time.strftime("%Y-%m-%d")def phone(module):"""Args:module: 模式Returns:"""if module =="1":return "188520011314"else:return "0532-81910921"
通过已实现 ParseContent 类 中的解析方法,即可完成解析,如下:
if __name__ == '__main__':# 创建解析方法对象 parse_context = ParseContent()# 加载 yaml 内容 , 如下yaml_context = Utils.load_yaml(r'F:\code\moc\conf\DataJob.yml')# 加载自定义模块parse_context.add_module_variables_functions(module_dirname=r"F:\code\moc",module_file_name="built_in.py")# 解析 yaml 中数据 result = parse_context.parse_content(yaml_context)print(result) # 解析字符串result_str = parse_context.parse_content("TIME: ${now_time()}")print(result)
执行如上代码,上述 Yaml文件内容,解析结果如下 :
# 解析 yaml 中数据
{"SignMap": [{"TIME": "2021-03-22"},{"PHONE": "0532-819109210"},{"TERMINALNAME": "alibaba"},{"DESC": "当前时间为:2021-03-22 ,联系电话为:0532-819109210"}]}# 解析字符串
TIME: 2021-03-23
解析方法 源码
为了方便阅读,源码中,将各模块代码合入一个模块中。
#!/usr/bin/env python
# -*- encoding: utf-8 -*-"""
@File : new_context_parse.py
@Contact : https://www.toutiao.com/c/user/token/MS4wLjABAAAAakx_PBJsQXpljEkaBcc0pEteSDMYxTbbBrlQ6F4p3yQ/@Modify Time @Author @Version @Desciption
------------ ------- -------- -----------
2021/3/22 00:47 软件测试开发技术栈 1.0 None
"""import ast
import json
import re
import yaml
import os
import sys
import types
import importlib
from collections import defaultdict
from collections import OrderedDict
from compat import basestring, builtin_str, numeric_types, strclass MyBaseError(Exception):passclass FileFormatError(MyBaseError):passclass ParamsError(MyBaseError):passclass NotFoundError(MyBaseError):passclass FileNotFound(FileNotFoundError, NotFoundError):passclass FunctionNotFound(NotFoundError):passclass VariableNotFound(NotFoundError):passclass LoadModule:def __init__(self):self.custom_module_info = {"variables": {},"functions": {}}self.project_working_directory = ""@staticmethoddef is_function(_type: types) -> bool:"""判断对象是否为函数Args:_type: 对象实际类型Returns:"""return isinstance(_type, types.FunctionType)@staticmethoddef is_variable(name: str, _type: types) -> bool:"""判断对象是否为变量,不含私有变量Args:name:_type:Returns:"""if callable(_type):return Falseif isinstance(_type, types.ModuleType):return Falseif name.startswith("_"):return Falsereturn True@staticmethoddef locate_file(start_file_or_dir_path: str, file_name: str) -> str:"""递归查询,返回文件绝对路径Args:start_file_or_dir_path: 起始目录file_name: 文件名称,包含文件类型后缀Returns: 不存在时,抛出异常Raises:exceptions.FileNotFound: 文件不存在"""if os.path.isfile(start_file_or_dir_path):start_dir_path = os.path.dirname(start_file_or_dir_path)elif os.path.isdir(start_file_or_dir_path):start_dir_path = start_file_or_dir_pathelse:raise FileNotFound("invalid path: {}".format(start_file_or_dir_path))file_path = os.path.join(start_dir_path, file_name)if os.path.isfile(file_path):return file_path# 当前工作目录if os.path.abspath(start_dir_path) in [os.getcwd(), os.path.abspath(os.sep)]:raise FileNotFound("{} not found in {}".format(file_name, start_file_or_dir_path))# 递归向上查找return LoadModule.locate_file(os.path.dirname(start_dir_path), file_name)@staticmethoddef locate_py(start_path, module_file_name) -> str or None:"""递归查询,返回文件绝对路径Args:start_file_or_dir_path: 起始目录file_name: 文件名称,包含文件类型后缀Returns: 不存在时,返回 NoneRaises:exceptions.FileNotFound: 文件不存在"""try:path = LoadModule.locate_file(start_path, module_file_name)return os.path.abspath(path)except FileNotFound:return None@staticmethoddef load_module_with_object(module_object: types.ModuleType) -> dict:"""通过模块对象的方式 加载 Python指定模块.获取函数与变量信息。Args:module_object (Object): python module 对象, module_object = importlib.import_module(module_name)Returns:dict: 指定python模块的变量和函数字典,字典格式:{"variables": {},"functions": {}}"""_custom_module_info = defaultdict(dict)for _name, _type in vars(module_object).items():if LoadModule.is_function(_type):_custom_module_info["functions"][_name] = _typeelif LoadModule.is_variable(_name, _type):if isinstance(_type, tuple):continue_custom_module_info["variables"][_name] = _typeelse:# 过滤掉私有变量、模块等passreturn _custom_module_infodef load_module_with_name(self, module_name: str) -> None:"""通过模块名字(不含)的方式 加载 Python指定模块.获取函数与变量信息。应该位于项目工作目录中Args:module_name: 模块名称, 不含后缀Returns:dict: 指定python模块的变量和函数字典,字典格式:{"variables": {},"functions": {}}"""imported_module = importlib.import_module(module_name)_custom_module_info = LoadModule.load_module_with_object(imported_module)# 更新self.custom_module_info.update(_custom_module_info)def load_specified_path_module(self, start_path: str, module_file_name_with_py: str) -> None:"""通过模块名字(含后缀)的方式 加载 Python指定模块.获取函数与变量信息。Args:start_path:module_file_name_with_py: 模块名字(含后缀)Returns:"""""" load .env, .py.api/testcases folder is relative to project_working_directoryArgs:module_file_name_with_py: start_path (str):module_file_name(str):"""module_path = LoadModule.locate_py(start_path, module_file_name_with_py)# 模块工作目录.if module_path:self.project_working_directory = os.path.dirname(module_path)else:# 当前目录兜底self.project_working_directory = os.getcwd()if module_path:# 将当前目录作为最优加载目录sys.path.insert(0, self.project_working_directory)module_name = os.path.splitext(module_file_name_with_py)[0]self.load_module_with_name(module_name)class Utils:"""工具类"""@staticmethoddef load_yaml(yaml_file_path: str) -> dict:"""加载 yaml文件Args:yaml_file_path: yaml文件路径,绝对或相对路径Returns:dict"""# 将yaml格式内容 转换成 dict类型with open(yaml_file_path, encoding="utf-8") as read_yaml:yaml_context_dict = yaml.load(read_yaml.read(), Loader=yaml.Loader)return yaml_context_dict@staticmethoddef string_value_number(possible_number: str) -> int or float or str:"""将允许为数字的字符串,解析为数字Args:possible_number: 可能为数字的字符串Returns:Examples:"9527" => 9527"9527.2" => 9527.3"abc" => "abc""$name" => "$name""""try:return ast.literal_eval(possible_number)except ValueError:return possible_numberexcept SyntaxError:return possible_number@staticmethoddef convert_list_to_dict(mapping_list: list) -> dict:""" 将列表转换为有序字典Args:mapping_list: 列表[{"a": 1},{"b": 2}]Returns:OrderedDict:{"a": 1,"b": 2}"""ordered_dict = OrderedDict()for map_dict in mapping_list:ordered_dict.update(map_dict)return ordered_dict@staticmethoddef extract_functions(content: str) -> list:""" 从字符串内容中提取所有函数,格式为${fun()}Args:content : 字符串的内容Returns:list: functions list extracted from string contentExamples:>>> Utils.extract_functions("${func(1)}")["func(1)"]>>> Utils.extract_functions("${func(a=1, b=2)}")["func(a=1, b=2)"]>>> Utils.extract_functions("/api/${func(1, 2)}")["func(1, 2)"]>>> Utils.extract_functions("/api/${func(1, 2)}?_s=${func2()}")["func(1, 2)", "func2()"]"""try:return re.findall(StaticVariable.FUNCTION_REGEXP, content)except TypeError:return []@staticmethoddef extract_variables(content: str) -> list:""" 从字符串内容中提取所有变量名,格式为$variableArgs:content : 字符串的内容Returns:list: 从字符串内容中提取的变量列表Examples:>>> Utils.extract_variables("$phone")["phone"]>>> Utils.extract_variables("/api/$phone")["phone"]>>> Utils.extract_variables("/$phone/$name")["phone", "name"]"""try:return re.findall(StaticVariable.VARIABLE_REGEXP, content)except TypeError:return []@staticmethoddef parse_string_variables(content: str, variables_mapping: dict) -> str:""" 用变量映射,替换出字符串内容中提取所有变量名。Args:content : 字符串的内容variables_mapping : 变量映射.Returns:str: 解析字符串内容。Examples:>>> content = '$TERMINAL_NAME'>>> variables_mapping = {"$TERMINAL_NAME": "alibaba"}>>> Utils.parse_string_variables(content, variables_mapping)"alibaba""""def get_mapping_variable(__variable_name: str):""" 从 variable_mapping 中获取变量。Args:__variable_name: 变量名称Returns:变量值.Raises:exceptions.VariableNotFound: 变量不存在"""try:return variables_mapping[__variable_name]except KeyError:# print variable_nameraise VariableNotFound("{} is not found.".format(__variable_name))variables_list = Utils.extract_variables(content)for variable_name in variables_list:variable_value = get_mapping_variable(variable_name)if "${}".format(variable_name) == content:content = variable_valueelse:if not isinstance(variable_value, str):variable_value = builtin_str(variable_value)content = content.replace("${}".format(variable_name),variable_value, 1)return content@staticmethoddef parse_function(content: str) -> dict:""" 从字符串内容中解析函数名和参数。Args:content : 字符串的内容Returns:dict:{"func_name": "xxx","func_args": [],"func_kwargs": {}}Examples:>>> Utils.parse_function("func()"){'func_name': 'func', 'func_args': [], 'func_kwargs': {}}>>> Utils.parse_function("func(1)"){'func_name': 'func', 'func_args': [1], 'func_kwargs': {}}>>> Utils.parse_function("func(1, 2)"){'func_name': 'func', 'func_args': [1, 2], 'func_kwargs': {}}>>> Utils.parse_function("func(a=1, b=2)"){'func_name': 'func', 'func_args': [], 'func_kwargs': {'a': 1, 'b': 2}}>>> Utils.parse_function("func(1, 2, a=3, b=4)"){'func_name': 'func', 'func_args': [1, 2], 'func_kwargs': {'a':3, 'b':4}}"""matched = StaticVariable.FUNCTION_REGEXP_COMPILE.match(content)if not matched:raise FunctionNotFound("{} not found!".format(content))function_meta = {"func_name": matched.group(1),"func_args": [],"func_kwargs": {}}args_str = matched.group(2).strip()if args_str == "":return function_metaargs_list = args_str.split(',')for arg in args_list:arg = arg.strip()if '=' in arg:key, value = arg.split('=')function_meta["func_kwargs"][key.strip()] = Utils.string_value_number(value.strip())else:function_meta["func_args"].append(Utils.string_value_number(arg))return function_meta@staticmethoddef get_mapping_function(function_name: str, functions_mapping: dict) -> types.FunctionType or None:""" 从functions_mapping中获取函数,如果没有找到,那么尝试检查是否内置函数。Args:function_name: 函数名称functions_mapping: 函数映射Returns:函数对象Raises:exceptions.FunctionNotFound: 函数没有定义"""if function_name in functions_mapping:return functions_mapping[function_name]try:# 判断是否是内置函数item_func = eval(function_name)if callable(item_func):return item_funcexcept (NameError, TypeError):raise FunctionNotFound("{} is not found.".format(function_name))class StaticVariable:# 变量正则规则VARIABLE_REGEXP = r"\$([\w_.]+)"# 函数正则规则FUNCTION_REGEXP = r"\$\{([\w_]+\([\$\w\.\-/_ =,]*\))\}"# 函数正则规则FUNCTION_REGEXP_COMPILE = re.compile(r"^([\w_]+)\(([$\w.\-/_ =,]*)\)$")class ParseContent:def __init__(self):self.variables_mapping = {}self.functions_mapping = {}def parse(self, content: (str, dict, list, numeric_types, bool, type)) -> list or dict or str:""" 解析变量|函数映射值Args:content :variables_mapping : 变量映射functions_mapping : 函数映射Returns:parsed content.Examples:>>> content = {'SignMap':[{'TIME': '${now_time()}'},{ 'PHONE': '${phone($MODULE)}'},{'TERMINALNAME': '$TERMINAL_NAME'}]}>>> variables_mapping = {'MODULE': '2', 'TERMINAL_NAME': 'alibaba'}>>> functions_mapping = {'now_time': '<function now_time at 0x00000142659A8C18>', 'phone': '<function phone at 0x00000142659B9AF8>', }>>> self.parse(content, variables_mapping){'SignMap':[{'TIME': '2021-03-20'},{ 'PHONE': '0532-819109210'},{'TERMINALNAME': 'alibaba'}]}}"""if content is None or isinstance(content, (numeric_types, bool, type)):return contentif isinstance(content, (list, set, tuple)):return [self.parse(item, )for item in content]if isinstance(content, dict):parsed_content = {}for key, value in content.items():parsed_key = self.parse(key)parsed_value = self.parse(value)parsed_content[parsed_key] = parsed_valuereturn parsed_contentif isinstance(content, basestring):_variables_mapping = self.variables_mapping or {}_functions_mapping = self.functions_mapping or {}content = content.strip()# 用求值替换函数content = self.parse_string_functions(content)# 用绑定值替换变量content = Utils.parse_string_variables(content, _variables_mapping)return contentdef update_original_context_var_func(self, _variables_mapping: dict, _functions_mapping: dict) -> None:"""将模块原始函数、变量更新到对象属性中Args:_variables_mapping:_functions_mapping:Returns:"""self.variables_mapping.update(_variables_mapping)self.functions_mapping.update(_functions_mapping)def update_context_variables(self, _variables: (str, list, dict)) -> None:"""更新上下文中的变量Args:_variables:Returns:"""if isinstance(_variables, list) or isinstance(_variables, dict):if isinstance(_variables, list):_variables = Utils.convert_list_to_dict(_variables)for variable_name, variable_value in _variables.items():variable_eval_value = self.parse(variable_value)self.variables_mapping[variable_name] = variable_eval_valueelse:variable_eval_value = self.parse(_variables)self.variables_mapping[_variables] = variable_eval_valuedef parse_string_functions(self, content: str) -> str:""" 用函数映射解析字符串内容。Args:content : 要解析的字符串内容。Returns:str: 解析字符串内容。Examples:>>> content = '${now_time()}'>>> self.parse_string_functions(content)'2021-03-20'"""functions_list = Utils.extract_functions(content)for func_content in functions_list:function_meta = Utils.parse_function(func_content)func_name = function_meta["func_name"]args = function_meta.get("func_args", [])kwargs = function_meta.get("func_kwargs", {})args = self.parse(args)kwargs = self.parse(kwargs)func = Utils.get_mapping_function(func_name, self.functions_mapping)eval_value = func(*args, **kwargs)func_content = "${" + func_content + "}"if func_content == content:content = eval_valueelse:# 字符串包含一个或多个函数或其他内容content = content.replace(func_content,str(eval_value), 1)return contentdef add_module_variables_functions(self, module_dirname, module_file_name) -> None:"""添加模块属性、函数Args:module_dirname:module_file_name:context:Returns:"""load_module = LoadModule()load_module.load_specified_path_module(module_dirname, module_file_name)custom_module_info = load_module.custom_module_info_variables_mapping = custom_module_info["variables"]_functions_mapping = custom_module_info["functions"]self.update_original_context_var_func(_variables_mapping, _functions_mapping)def parse_content(self, context):"""解析内容Args:context:Returns:"""self.update_context_variables(context)return self.parse(context)if __name__ == '__main__':parse_context = ParseContent()# 加载 yaml 内容 ,如下yaml_context = Utils.load_yaml(r'E:\PythonCode\MOC\conf\DataJob.yml')# 加载指定 built_in 模块parse_context.add_module_variables_functions(module_dirname=r"E:\PythonCode\MOC",module_file_name="built_in.py")# 加载指定 common 模块parse_context.add_module_variables_functions(module_dirname=r"E:\PythonCode\MOC",module_file_name="common.py")# 解析 yaml 中数据 result = parse_context.parse_content(yaml_context)print(result)# {'SignMap': [{'TIME': '2021-03-23'}, {'PHONE': '0532-819109210'}, {'TERMINALNAME': 'alibaba'}]}# 解析字符串result_str = parse_context.parse_content("TIME: ${now_time()}")print(result_str)# TIME: 2021-03-23
上述代码已经完成改造,支持添加多个自定义模块,解耦模块加载和字符串解析功能。
一句话送给你们:
世界的模样取决于你凝视它的目光,自己的价值取决于你的追求和心态,一切美好的愿望,不在等待中拥有,而是在奋斗中争取。
如果你
①从事功能测试,想进阶自动化测试
②在测试界混了1、2年,依然不会敲代码
③面试大厂却屡屡碰壁
我邀你进群吧!来吧~~测试员,313782132(Q群里有技术大牛一起交流分享,学习资源的价值取决于你的行动,莫做“收藏家”)获取更多大厂技术、面试资料
金九银十面试季,跳槽季。给大家整理的资料,整体是围绕着【软件测试】来进行整理的,主体内容包含:python自动化测试专属视频、Python自动化详细资料、全套面试题等知识内容。愿你我相遇,皆有所获! 关注我领取~
如果文章对你有帮助,麻烦伸出发财小手点个赞,感谢您的支持,你的点赞是我持续更新的动力。
推荐阅读:
什么样的人适合从事软件测试工作?
谈谈从小公司进入大厂,我都做对了哪些事?
想转行做软件测试?快来看看你适不适合
软件测试从自学到工作,软件测试学习到底要怎样进行?
软件测试工程师简历项目经验怎么写?–1000个已成功入职的软件测试工程师简历范文模板(真实简历)