为什么派生类中的测试会重新运行父类测试?

Why do tests in derived classes rerun the parent class tests?

提问人:wim 提问时间:11/3/2015 更新时间:7/24/2017 访问量:3198

问:

当测试设置中存在大量重叠时,可以使用继承来保持 DRY。但这会导致不必要的重复测试执行问题:

from unittest import TestCase

class TestPotato(TestCase):
    def test_in_parent(self):
        print 'in parent'

class TestSpud(TestPotato):
    def test_in_child(self):
        print 'in child'

测试此模块将运行两次。test_in_parent

$ python -m unittest example
in parent
.in child
.in parent
.
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

为什么?这是设计使然吗?可以通过以某种方式配置测试运行程序来禁用它吗?

我可以通过将设置移动到未发现的类中来解决此问题,然后使用多重继承,但这似乎有点笨拙且没有必要。

注意:同样的问题也发生在其他运行器中,例如 nose () 和 pytest (nosetests -s example.pypy.test example.py)

python pytest python-unittest nosetests

评论

3赞 jonrsharpe 11/3/2015
因为他们继承了父母的测试方法,所以当查看他们(或它所做的任何事情)以寻找开始的方法时,它也会找到继承的方法。我不认为解决这个问题需要多重继承;将两者都需要的东西抽象到第三个没有方法的、不可发现的类,并让它们都继承它。unittestdir__dict__test_test_
0赞 dm03514 11/3/2015
如果子类的父类包含以 test 为前缀的方法,则该子类将显示具有这些方法的子类。这是python OOP。我不认为将设置方法移动到 mixin 或作为单独的基类似乎很笨拙,而且可能是 DRYer
0赞 Shashank 11/3/2015
对于不同“组”测试的 mixin 来说,这似乎是一个很好的用例,可以动态创建您需要的确切测试......树继承在这里看起来不是正确的模型。
0赞 user10664542 11/15/2023
答案似乎是“Python OOP 坏了——但 OOP 无论如何都不好”。我同意 Python OOP 被破坏了,但 OOP 在许多情况下非常有用。构图也不错,但 OOP 还不错,在某些情况下非常有用。我需要所有测试用例都具有一些在基类中设置的公共变量,以便每个类都没有指向所有测试用例中我需要的类的变量的副本 - 这是 OOP 的一个点。

答:

6赞 Łukasz Rogalski 11/3/2015 #1

测试运行程序查找以 开头的所有方法。继承的方法存在于子类中 - 因此它们被检测为要运行的测试。 为了避免这种情况,您应该提取父类中的通用代码,并且不要继承任何实际测试。test

from unittest import TestCase

class PotatoTestTemplate(TestCase):
    def setUp():
        pass

class PotatoTest1(PotatoTestTemplate):
    def test1(self):
        pass

class PotatoTest2(PotatoTestTemplate):
    def test1(self):
        pass

评论

0赞 wim 10/27/2016
我已经确定了与此类似的模式 - 而不是我使用 .它不是一个,它更像是一个混合体。然后,如果需要,我会在任一测试中使用和进行额外的设置。PotatoTestTemplatePotatoSetup(object)TestCasePotatoTest(PotatoSetup, TestCase)SpudTest(PotatoSetup, TestCase)
1赞 lee penkman 10/27/2016 #2

我看到人们使用的另一种解决方法是嵌套类不会作为鼻子测试的一部分运行,例如

from unittest import TestCase
class NotTested:
    class TestPotato(TestCase):
        def test_in_parent(self):
            print 'in parent'

class TestSpud(NotTested.TestPotato):
    def test_in_child(self):
        print 'in child'

我尝试过的一种解决方法是使用多重继承,以便 TestPotato 类扩展对象,并且 TestSpud 确实从 TestCase 和 TestPotato 扩展 例如

from unittest import TestCase

class TestPotato(object):
    def test_in_parent(self): 
        # still gets ran twice because
        # nosetests runs anything that starts with test_* :(
         print 'in parent'

class TestSpud(TestCase, TestPotato):
    def test_in_child(self):
        print 'in child'

但这实际上对我不起作用,我希望它能用,因为你不需要添加代码嵌套......但无论如何,看起来使用多重继承是不好

1赞 Larry 7/24/2017 #3

如果您只需要来自其他测试类的测试设置,则可以这样做:

from unittest import TestCase

class TestPotato(TestCase):
    def setUp(self):
        print('fixtures here')

    def test_in_parent(self):
        print 'in parent'


class TestSpud(TestCase):
    def setUp(self):
        TestPotato.setUp(self)

    def test_in_child(self):
        print 'in child'