如何正确导入测试类以继承自,而不是 运行 作为测试

How can I import a testclass properly to inherit from, without it being run as a test

上下文

我有一个测试 class,我的所有测试都继承自该测试。它本身不能运行,因为它实际上不包含任何设置信息

我想添加一个由所有测试执行的测试(将其添加到基础class 似乎合乎逻辑)

但现在我注意到我导入的 basetestclass( => Foo) 被检测为测试本身和 运行s 并且在报告中可见

代码

基础 class 在 base.py

from unittest import TestCase

class Foo(TestCase):
    @classmethod
    def setUpClass(cls):
        # prepare the generic setup stuff based on what is defined in the child class
        print("setupclass Foo done")

    def test_run_in_all_inherited_tests(self):
        print("fooBar")
        assert True

真正的考验在test_something.py

from base import Foo # <= This is being detected as a testclass object and thus will be executed

class TestFoo(Foo):
    @classmethod
    def setUpClass(cls):
        # define specific test setup
        super().setUpClass()
        print("setup TestFoo done")

    def test_pass(self):
        pass

    def test_assert(self):
        assert False

这会触发对导入的 Foo

的测试运行

问题

如何导入 Foo 而不会被检测为 'test' 如果我在所有测试中删除 运行 的测试,一切都很好。

向 Foo 添加 @nottest 装饰器将无法工作,从那时起所有继承的 classes 都被定义为 nottest。

它需要 运行 nosepytestunittest 测试 运行 人

我注意到如果我像下面这样更改导入语句,它也会起作用。但这意味着要在不同的回购协议中调整数百个测试文件。 (我想避免这种情况)

import base
class TestFoo(base.Foo):

答案的关键似乎是每个测试都有一个属性__test__,当它是测试时设置为True

当 class 不应该是测试时将其设置为 False 将让测试收集器忽略此 class。

答案假定我只能在 base.py

中进行更改

在 python 3.9 中 class 方法和 属性 装饰器可以组合,所以我为此写了一个单独的答案

< py3.9 的答案

基础 class 在 base.py

from unittest import TestCase

class MetaFoo(type):
    @property
    def __test__(cls):
        return cls != Foo

class Foo(TestCase, metaclass=MetaFoo):
    @classmethod
    def setUpClass(cls):
        # prepare the generic setup stuff based on what is defined in the child class
        print("setupclass Foo done")

    def test_run_in_all_inherited_tests(self):
        print("fooBar")
        assert True

回答 >= py3.9

基础 class 在 base.py

from unittest import TestCase

class Foo(TestCase):
    @classmethod
    @property
    def __test__(cls):
        return cls != Foo

    @classmethod
    def setUpClass(cls):
        # prepare the generic setup stuff based on what is defined in the child class
        print("setupclass Foo done")

    def test_run_in_all_inherited_tests(self):
        print("fooBar")
        assert True

实测

test_something.py

from base import Foo # <= This will not be detected as a test anymore as __test__ returns False

class TestFoo(Foo):
    @classmethod
    def setUpClass(cls):
        # define specific test setup
        super().setUpClass()
        print("setup TestFoo done")

    def test_pass(self):
        pass

    def test_assert(self):
        assert False

这不再触发导入的 Foo 的测试运行