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.
这将跳过的测试标记为
好吧,我找到了一种方法来拥有我想要的功能。我把装潢师改成:
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个空格。有更聪明的方法吗?