【问题标题】:Adding test methods dynamically using decorator使用装饰器动态添加测试方法
【发布时间】:2015-01-03 05:14:59
【问题描述】:

在过去的几个月里,我一直在使用 DDT 参数化我的测试,并取得了巨大的成功。我现在的问题是我似乎无法注入列表变量作为我的数据源。这样做似乎会混淆 DDT,导致它无法参数化我的测试。我开始创建自己的解决方案,但我似乎无法弄清楚最后一部分。

这是迄今为止我所拥有的装饰器 -

def data(*values):
    def aaa(func):
        def wrapper(self, *args, **kwargs):
            pass
#             return func(self, *args, **kwargs)
        wrapper.func_name = func.__name__ + 't'
        wrapper.values = values
        return wrapper
    return aaa


def c(cls):
    for name, method in list(cls.__dict__.items()):
        if hasattr(method, 'values'):
            for ticket in method.values[0]:
                test_name = mk_test_name(method.func_name, ticket)
                print(test_name)
                setattr(cls, test_name, method(cls, ticket))
    return cls

我就这样使用它 -

@c
class IntegrationTests(APITestCase):
    tickets = [1, 2, 3, 4]

    @data(tickets)
    def tes(self, t):
        print(t)

如何让 Python 测试框架识别出我是通过装饰器添加的?我知道这些方法已添加,因为在 PDB 中发出 dir 命令会显示它们。这样做的目标是我会复制我为列表中的每个项目装饰的测试。对于那些想知道为什么wrapper() 没有代码的人,我这样做是因为取消注释返回调用的行会导致我装饰的方法在没有参数的情况下执行,从而导致错误。

在我的示例中,我希望执行 4 个不同名称的测试。

【问题讨论】:

  • 你有python 3.4吗?实现您想要的最佳方法是使用子测试 -- docs.python.org/3/library/…
  • 我是!不知道子测试甚至是一件事。如果你发布它,我会接受你的答案。谢谢。

标签: python python-3.x decorator python-decorators data-driven-tests


【解决方案1】:

最好的解决方案是在 python 3.4 中使用 unittest 的子测试功能。文档找到 here 并使用如下:

class NumbersTest(unittest.TestCase):

    def test_even(self):
        """
        Test that numbers between 0 and 5 are all even.
        """
        for i in range(0, 6):
            with self.subTest(i=i):
                self.assertEqual(i % 2, 0)

对于不能使用python 3.4的人,以下是穷人的替代品。

class sub_test_data(object):

    def __init__(self, *test_data):
        self.test_data = test_data

    def __call__(self, func):
        func.sub_test_data = self.test_data
        func.has_sub_tests = True
        return func

def create_test_driver(func, *args):
    def test_driver(self):
        try:
            func(self, *args)
        except AssertionError as e:
            e.args += ({"test_args": args},)
            raise
    return test_driver  

def create_sub_tests(cls):
    for attr_name, func in list(vars(cls).items()):
        if getattr(func, "has_sub_tests", False):
            for i, value in enumerate(func.sub_test_data):
                test_name = 'test_{}_subtest{}'.format(attr_name, i)
                setattr(cls, test_name, create_test_driver(func, value))
    return cls

@create_sub_tests
class NumbersTest(unittest.TestCase):
    tickets = [0, 1, 2, 3, 4, 5]

    @sub_test_data(*tickets)
    def even(self, t):
        self.assertEqual(t % 2, 0)

【讨论】:

  • 哇!如果可以的话,我会 +2。
猜你喜欢
  • 2012-03-15
  • 2011-07-25
  • 1970-01-01
  • 2021-01-07
  • 2013-04-04
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2017-06-19
相关资源
最近更新 更多