首页 > 其他分享 >关键字 开发-05 读取yaml文件内容动态生成用例

关键字 开发-05 读取yaml文件内容动态生成用例

时间:2023-11-27 20:46:42浏览次数:44  
标签:code co file 用例 05 name yaml func mod

前言

在第一篇文章中,我们讲过了通过钩子函数pytest_collect_file可以收集到yaml格式的用例,并且可以生成测试用例。
想要动态生成测试用例,也就是动态生成测试函数,然后pytest收集到test开头的func,执行测试函数。关键代码如下所示:

def run_function(*args, **kwargs):
    print("测试用例-----")
    # 向 module 中加入test 函数
    setattr(MyModule, "test_run", run_function)

由上面可以知道,目前生成测试函数,我们是写死的run_function()。这样写虽然也能把读到的yaml文件按关键字去执行,但是定义的函数是写死的,不能给函数动
态添加一些参数。我想实现定义一个函数,动态添加不同参数,就无法实现了,于是需要找到一个可以动态生成函数的方法,并且能给函数动态添加参数。

1. 动态生成函数

目前通过查看资料,发现动态生成函数有以下几种方式:
1. 方式一:已有函数的基础上,创建新函数
2. 方式二:配合compile函数 创建函数
3. 方式三:一个函数动态创建多个函数(重要)
接下来我会使用方式三来动态创建函数的操作。该方法可以参考:https://zhuanlan.zhihu.com/p/386276353
其生成函数的过程我不讲,具体可以看上面的链接,我就直接讲怎么用,该方法的源码如下:

# utils/create_funtion.py
import sys
import types
from typing import Any, Callable, Mapping, Sequence
from inspect import Parameter, Signature
def create_function_from_parameters(
        func: Callable[[Mapping[str, Any]], Any],
        parameters: Sequence[Parameter],
        documentation=None,
        func_name=None,
        func_filename=None):
    new_signature = Signature(parameters) # Checks the parameter consistency
    def pass_locals():
        return dict_func(locals()) # noqa: F821 TODO
    code = pass_locals.__code__
    mod_co_argcount = len(parameters)
    mod_co_nlocals = len(parameters)
    mod_co_varnames = tuple(param.name for param in parameters)
    mod_co_name = func_name or code.co_name
    if func_filename:
        mod_co_filename = func_filename
        mod_co_firstlineno = 1
    else:
        mod_co_filename = code.co_filename
        mod_co_firstlineno = code.co_firstlineno
    if sys.version_info >= (3, 8):
        modified_code = code.replace(
            co_argcount=mod_co_argcount,
            co_nlocals=mod_co_nlocals,
            co_varnames=mod_co_varnames,
            co_filename=mod_co_filename,
            co_name=mod_co_name,
            co_firstlineno=mod_co_firstlineno,
            )
    else:
        modified_code = types.CodeType(
            mod_co_argcount,
            code.co_kwonlyargcount,
            mod_co_nlocals,
            code.co_stacksize,
            code.co_flags,
            code.co_code,
            code.co_consts,
            code.co_names,
            mod_co_varnames,
            mod_co_filename,
            mod_co_name,
            mod_co_firstlineno,
            code.co_lnotab
            )
    default_arg_values = tuple(p.default for p in parameters if p.default != Parameter.empty) #!argdefs "starts from the right"/"is right-aligned"
    modified_func = types.FunctionType(modified_code, {'dict_func': func, 'locals': locals}, name=func_name,argdefs=default_arg_values)
    modified_func.__doc__ = documentation
    modified_func.__signature__ = new_signature
    return modified_func
def foo(arg):
    print(arg)
    return "x"
f = create_function_from_parameters(
    func=foo,
    parameters=[Parameter('x', Parameter.POSITIONAL_OR_KEYWORD)],
    documentation="some doc",
    func_name="bar",
    func_filename="main.py",
)
# 上面等价于下面的函数
def bar(a):
    """some doc"""
    foo({'x': a})  # bar函数的函数体等价于foo({’x‘: a})
# print(f('1111'))

于是我们把这个方法写到我们的钩子函数pytest_collect_file中。

# conftest.py
from pytest import Module, Function
import types
from utils.create_function import create_function_from_parameters
from inspect import Parameter

def pytest_collect_file(file_path, parent):
    # 查找test开头的文件
    if file_path.suffix in ['.yml', '.yaml'] and (file_path.name.startswith('test') or file_path.name.endstartswith('test')):
        print(f'yaml文件路径:{file_path}')
        print(f'yaml文件路径名称:{file_path.stem}')

        # 构造 pytest 框架的 Module,module由Package构建,Package由系统构建
        py_module = Module.from_parent(parent, path=file_path)

        # 动态创建测试module模块(.py文件),这里才能给下面的_getobj进行导入
        MyModule = types.ModuleType(file_path.stem)

        from utils.read_file import read_yaml
        from pathlib import Path
        file_path = Path(__file__).parent.joinpath('data', 'login.yml')
        raw_data = read_yaml(file_path)['data']
        for key, value in raw_data:

            def foo(arg):
                print(f"执行的参数: {arg}")
                print(f"执行的内容: {value}")
            f = create_function_from_parameters(func=foo,
                                                parameters=[Parameter('request', Parameter.POSITIONAL_OR_KEYWORD)],
                                                documentation="some doc",
                                                func_name=key,
                                                func_filename="main.py")
            # 向 module 中加入test 函数
            setattr(MyModule, key, f)

        # 重写_getobj,返回自己定义的Mymodule
        py_module._getobj = lambda: MyModule

        return py_module

我们在项目目录下创建一个test_x.yml文件,来测试是否动态创建成功。

# test_x.yml
test_x1:
  print: xxxxxx111


test_x2:
  print: xxx2222

pytest .\test_x.yml -s执行后,如下图,发现动态创建成功,且request参数也动态传入。

参考来源:https://zhuanlan.zhihu.com/p/386276353

标签:code,co,file,用例,05,name,yaml,func,mod
From: https://www.cnblogs.com/dack-zt-deng/p/17860400.html

相关文章

  • 16位微控制器PIC24FJ256GL405-I/PT、PIC24FJ128GU408-I/PT、PIC24FJ32GB002T-I/ML(MCU)
    一、PIC24FJ256GL405-I/PT、PIC24FJ128GU408-I/PT16位微控制器PIC24FJ-GU4/GL416位微控制器(MCU)提供高达512KB的双分区闪存,支持实时无线(OTA)更新和EEPROM仿真。除了若干内核独立外设(CIP),PIC24FJ-GU4/GL4MCU还包括一个全速USB和一个支持动画的分段LCD控制器。这些器件......
  • py05-循环
    五、循环:1、while循环while条件:条件满足时,做的事情1条件满足时,做的事情2......注意:条件需提供布尔类型结果,True继续,False停止;需要循环终止条件,否则将无限循环2、for循环for变量in可迭代对象循环内容3、总结:(1)while循环的循环条件是自定义的,......
  • Datewhale学习笔记05
    Datewhale学习笔记5$\textcolor{blue}{Datewhale学习笔记}$$\textcolor{red}{chap5}$聪明办法学Python2ndEditionChapter5循环Loopfor循环和循环范围for循环的特点基于提供的范围,重复执行特定次数的操作In[1]defsumFromMToN(m,n):total=0#注意:ra......
  • Linux05
           在Linux课程的第四章中我学了文件权限,基本权限为U(owner:属主)、G(group:属组)、O(other:其他用户),Linux系统通过U、G、O将用户分为三类,并对这三类用户分别设置三种基本权限,这种设置权限的方式称作UGO方式。读取权限(read):r,数字设定为4;写入权限(write):w,数字设定为2;执行权限......
  • # 2023-2024-1 学号:20231305 《计算机基础与程序设计》第9周学习总结
    2023-2024-1学号:20231305《计算机基础与程序设计》第9周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2022-2023-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(如2022-2023-1计算机基础与程序设计第一周作业)这个作业的目标<自学教材计算......
  • 05-列表和表单
    typora-copy-images-to:media第01阶段.前端基础.列表和表单1.列表标签(重点)学习目标理解无序列表的应用场景自定义列表的应用场景应用无序列表语法自定义列表语法问?前面我们知道表格一般用于数据展示的,但是网页中还是有很多跟表格类似的布局,如下图~~我们......
  • 2023-2024-1 20231405《计算机基础与程序设计》第九周学习总结
    2023-2024-120231405《计算机基础与程序设计》第九周学习总结作业信息作业属于哪个课程https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP作业要求在哪里https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP/homework/13009作业的目标自学《计算......
  • AcWing 3305. 作物杂交 (spfa建边变形版本
    package蓝桥杯;importjava.util.Arrays;importjava.util.LinkedList;importjava.util.Queue;importjava.util.Scanner;publicclasslanqiao1443{staticfinalintN=2010,M=2*100010;staticint[]h,e,ne,w,target;staticint[]dist;......
  • [ARC105E] Keep Graph Disconnected
    题目链接好题。如果\(1\)和\(n\)一直联通,开始即结束。如果\(n\mod4=1\),那么\(\frac12x(x+1)+\frac12(n-x)(n-x+1)\)为偶数。如果\(n\mod4=3\),那么\(\frac12x(x+1)+\frac12(n-x)(n-x+1)\)为奇数。这两种情况最后连的边的数量奇偶固定,结合\(m\)的大小可以算出......
  • day05 K8S网络组件的深度剖析 (1.10.1 -1.10.3)
    一、K8S网络组件的深度剖析上1、认识FlannelFlannel是专为kubernetes定制的三层网络解决方案,主要用于解决容器的跨主机通信问题优势:kubernetes发行版都可以默认安装Flannel容器安装和配置中小型网络架构首选不需要专用的数据存储劣势:性能损耗高不支持NetworkPolic......