通过使用decorator和元类跳过python中除一个以外的所有单元测试

Skipping all unit tests but one in Python by using decorators and metaclasses

我正在为一个通过USB端口通信命令并检查其响应的MCU编写单元测试。如果一个单元测试失败,我可以在MCU中进行一些调试。因此,我想禁用除要在mcu端调试的单元测试之外的所有单元测试,因为如果我在某个地方设置断点,它可能会被另一个具有不同命令的单元测试触发。

我找到了这个代码,它是一个修饰符,可以跳过所有没有属性的单元测试。

1
2
3
4
def skipUnlessHasattr(obj, attr):
    if hasattr(obj, attr):
        return lambda func: func
return unittest.skip("{!r} doesn't have {!r}".format(obj, attr))

为了使它更简单,我删除了attr参数并静态地将其更改为"stepdebug",这是一个属性,我只想在一个unittest中设置它,以便对其进行调试。

所以下一步是我自动地将它应用于我的所有类方法。在网上阅读之后,我发现下面的代码使用一个元类来用上面的修饰器修饰所有方法。https://stackoverflow.com/a/6308016/3257551

1
2
3
4
5
6
7
8
9
def decorating_meta(decorator):
class DecoratingMetaclass(type):
    def __new__(self, class_name, bases, namespace):
        for key, value in list(namespace.items()):
            if callable(value):
                namespace[key] = decorator(value)
        return type.__new__(self, class_name, bases, namespace)

return DecoratingMetaclass

所以我的最小工作示例是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import unittest

def decorating_meta(decorator):
    class DecoratingMetaclass(type):
        def __new__(self, class_name, bases, namespace):
            for key, value in list(namespace.items()):
                if callable(value):
                    namespace[key] = decorator(value)
            return type.__new__(self, class_name, bases, namespace)

    return DecoratingMetaclass

def skipUnlessHasattr(obj):
    if hasattr(obj, 'StepDebug'):
        return lambda func : func
    return unittest.skip("{!r} doesn't have {!r}".format(obj, 'StepDebug'))

class Foo(unittest.TestCase):
    __metaclass__ = decorating_meta(skipUnlessHasattr)
    def test_Sth(self):
        self.assertTrue(False)

if __name__ == '__main__':
    unittest.main()

我得到的错误是:

1
AttributeError: 'Foo' object has no attribute '__name__'

从我读到的内容来看,当你有一个实例而不是一个类时,会发生这种情况,但我不太明白如何使用这些信息来解决我的问题。

有人能帮忙吗?


https://stackoverflow.com/a/44804070/1587329使用修饰符,通过环境参数初始化

1
MCU = os.getenv('MCU', False)

以及修饰通过f.ex排除的测试类和/或方法。

1
@unittest.skipIf(MCU)

这可以称为

1
MCU=1 python # test file etc

The only minor thing with this is that the output doesn't report all the other tests as skipped but rather as a success.

这将跳过的测试标记为s


好吧,我找到了一种方法来拥有我想要的功能。我把装潢师改成:

1
2
3
4
5
6
7
8
9
def skipUnlessHasattr(obj):
    if hasattr(obj, 'StepDebug'):
        def decorated(*a, **kw):
            return obj(*a, **kw)
        return decorated
    else:
        def decorated(*a, **kw):
            return unittest.skip("{!r} doesn't have {!r}".format(obj, 'StepDebug'))
        return decorated

现在,除了添加了属性stepdebug的测试外,所有测试都被跳过。

唯一的小问题是,输出不会将所有其他测试报告为跳过,而是报告为成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..F..
======================================================================
FAIL: test_ddd (__main__.Foo)
----------------------------------------------------------------------
Traceback (most recent call last):
  File"./Documents/programs/Python/mwe.py", line 23, in     decorated
    return obj(*a, **kw)
  File"./Documents/programs/Python/mwe.py", line 39, in     test_ddd
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 5 tests in 0.014s

FAILED (failures=1)

P.S.为什么在缩进4个空格后复制输出时不进入代码块?我也试过8个空格,但不起作用。最后,我在每行中添加了4个空格。有更聪明的方法吗?