首页 > 其他 > 详细

ddt参数化,ddt源码解析修改,修改ddt参数化的用例名

时间:2021-01-18 14:34:35      阅读:26      评论:0      收藏:0      [点我收藏+]

基本使用

下载  pip install ddt  ,ddt数据驱动只能适用于unittest子类的类装饰器。

  • 单个参数参数化:
import unittest
from ddt import ddt, data, unpack search_data = (data1, data2, data3) # 单个参数 @ddt class testDDT(unittest.TestCase): # 单个参数 @data(*search_data) # 传入可序列换对象,进行拆分 def testddt(self, data): print(data) if __name__ == __main__: unittest.main()
"""
result:

  data1
  data2
  data3

"""
  • 多个参数参数化:
import unittest

from ddt import ddt, data, unpack

search_datas = (
    [data1, data2, data2],
    [code1, code2, code3],
)  # 多个参数


@ddt
class testDDT(unittest.TestCase):

    # 多个参数
    @data(*search_datas) # data传入可序列化对象,会进行第一次拆分
    @unpack # unpack 将data序列化后的值再次判断,如果是列表或者数组,再次拆分
    def testddts(self, *args, **kwargs):
        print(args)
        print(kwargs)


if __name__ == __main__:
    unittest.main()
"""
result:

(‘data1‘, ‘data2‘, ‘data2‘)
{}
(‘code1‘, ‘code2‘, ‘code3‘)
{}

"""
  • 文件参数化(支持json yaml):
import os
import unittest

from ddt import ddt, data, unpack, file_data

search_datas = (
    [data1, data2, data2],
    [code1, code2, code3],
)  # 多个参数


@ddt
class testDDT(unittest.TestCase):

    # 文件参数化
    @file_data(os.path.join(ROOT_DIR, "params", "mysql_mask_all_types.yaml")) # 文件路径
    def test_file_data(self, **kwargs):
        print(kwargs)


if __name__ == __main__:
    unittest.main()

源码分析

主要函数和装饰器

  • @data:计算了case index和将传入的序列话参数赋值给 DATA_ATTR
def data(*values):
    """
    Method decorator to add to your test methods.

    Should be added to methods of instances of ``unittest.TestCase``.

    """
    # print("data")
    # print(values)
    global index_len
    index_len = len(str(len(values)))
    return idata(values)
def idata(iterable):
"""
Method decorator to add to your test methods.

Should be added to methods of instances of ``unittest.TestCase``.

"""
def wrapper(func):
setattr(func, DATA_ATTR, iterable)
return func
return wrapper
  • @unpack:给函数赋予UNPACK_ATTR 为 True的一个属性
def unpack(func):
    """
    Method decorator to add unpack feature.

    """
    setattr(func, UNPACK_ATTR, True)
    return func
  • @file_data 拆分解析的json文件、yaml文件
def file_data(value, yaml_loader=None):

    def wrapper(func):
        setattr(func, FILE_ATTR, value)
        if yaml_loader:
            setattr(func, YAML_LOADER_ATTR, yaml_loader)
        return func

    return wrapper

ddt参数化的用例名

ddt默认源码为:支持两种格式如下

@unique
class TestNameFormat(Enum):
    """
    An enum to configure how ``mk_test_name()`` to compose a test name.  Given
    the following example:

    .. code-block:: python

        @data("a", "b")
        def testSomething(self, value):
            ...

    if using just ``@ddt`` or together with ``DEFAULT``:

    * ``testSomething_1_a``
    * ``testSomething_2_b``

    if using ``INDEX_ONLY``:

    * ``testSomething_1``
    * ``testSomething_2``

    """
    DEFAULT = 0
    INDEX_ONLY = 1

ddt 源码修改

  • 修改参数化复杂的格式嵌套(字典),修改后可支持序列化 {‘a‘:[‘a1‘,‘a2‘],}格式,当然可根据自己所需格式进行调整
原始:
def data(*values):
    """
    Method decorator to add to your test methods.

    Should be added to methods of instances of ``unittest.TestCase``.

    """
    # print("data")
    # print(values)
    global index_len
    index_len = len(str(len(values)))
    return idata(values)

def idata(iterable):
    """
    Method decorator to add to your test methods.

    Should be added to methods of instances of ``unittest.TestCase``.

    """
    def wrapper(func):
        setattr(func, DATA_ATTR, iterable)
        return func
    return wrapper

修改为:
def data(*values, **kwargs):
    """
    Method decorator to add to your test methods.

    Should be added to methods of instances of ``unittest.TestCase``.

    """
    # print("data")
    # print(values)
    global index_len
    index_len = len(str(len(values)))
    return idata(values, **kwargs)


def idata(iterable, **kwargs):
    """
    Method decorator to add to your test methods.

    Should be added to methods of instances of ``unittest.TestCase``.

    """

    def wrapper(func):
        setattr(func, DATA_ATTR, iterable)
        if kwargs:
            new = [[i, j] for i, v in kwargs.items() for j in v]
            setattr(func, DATA_ATTR, new)
            setattr(func, UNPACK_ATTR, True)
        return func

    return wrapper

 

  • 修改用例名称格式可以找到源码  mk_test_name 函数进行调整,根据自身需求调整
def mk_test_name(name, value, index=0, name_fmt=TestNameFormat.DEFAULT):

    # Add zeros before index to keep order
    index = "{0:0{1}}".format(index + 1, index_len)
    if name_fmt is TestNameFormat.INDEX_ONLY or not is_trivial(value):
        return "{0}_{1}".format(name, index)
    try:
        if isinstance(value, tuple) or isinstance(value, list):  # 添加
            value = "_".join([str(i) for i in value])  # 添加
        else:  # 添加
            value = str(value)
    except UnicodeEncodeError:
        # fallback for python2
        value = value.encode(ascii, backslashreplace)
    test_name = "{0}_{1}_{2}".format(name, index, value)
    return re.sub(r\W|^(?=\d), _, test_name)
  • 修改data和file_data同时装饰参数化:可以找到源码的ddt 函数,原本的ddt函数子进行单独的if 判断,只需我们增加判断即可

 

def ddt(arg=None, **kwargs):
    
    fmt_test_name = kwargs.get("testNameFormat", TestNameFormat.DEFAULT)

    def wrapper(cls):
        for name, func in list(cls.__dict__.items()):
            if hasattr(func, DATA_ATTR) and hasattr(func, FILE_ATTR):
                file_attr = getattr(func, FILE_ATTR)
                data_data = getattr(func, DATA_ATTR)
                process_file_data(cls, name, func, file_attr, data_data)
                delattr(cls, name)
            elif hasattr(func, DATA_ATTR):
                for i, v in enumerate(getattr(func, DATA_ATTR)):
                    test_name = mk_test_name(
                        name,
                        getattr(v, "__name__", v),
                        i,
                        fmt_test_name
                    )
                    test_data_docstring = _get_test_data_docstring(func, v)
                    if hasattr(func, UNPACK_ATTR):
                        if isinstance(v, tuple) or isinstance(v, list):
                            add_test(
                                cls,
                                test_name,
                                test_data_docstring,
                                func,
                                *v
                            )
                        else:
                            # unpack dictionary
                            add_test(
                                cls,
                                test_name,
                                test_data_docstring,
                                func,
                                **v
                            )
                    else:
                        add_test(cls, test_name, test_data_docstring, func, v)
                # if not hasattr(func, FILE_ATTR):
                delattr(cls, name)
            elif hasattr(func, FILE_ATTR):
                file_attr = getattr(func, FILE_ATTR)
                process_file_data(cls, name, func, file_attr)
                delattr(cls, name)

        return cls

    # ``arg`` is the unittest‘s test class when decorating with ``@ddt`` while
    # it is ``None`` when decorating a test class with ``@ddt(k=v)``.
    return wrapper(arg) if inspect.isclass(arg) else wrapper

 

ddt参数化,ddt源码解析修改,修改ddt参数化的用例名

原文:https://www.cnblogs.com/buding-01/p/14292280.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!