【问题标题】:overloading unittest.testcase in python在python中重载unittest.testcase
【发布时间】:2013-09-30 19:27:24
【问题描述】:

我正在尝试通过子类化 unittest.testcase 类来创建自定义单元测试框架,但在处理 __init__ 方法时似乎犯了一个错误。

我无法弄清楚为什么ComplexTest 的构造函数没有在BasicTest 的构造函数之前被调用,并且异常似乎也与我的构造函数有关。

我对 Python 还是很陌生,因此非常欢迎任何有关如何解决这个特定问题或我的用例的替代架构的帮助。

谢谢!

1) test_framework.py

import unittest

class BasicTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        print('BasicTest.__init__')
        super(unittest.TestCase, self).__init__(*args, **kwargs)

    def setUp(self):
        print('BasicTest.setUp')
        super(unittest.TestCase, self).tearDown()

    def tearDown(self):
        print('BasicTest.tearDown')
        super(unittest.TestCase, self).tearDown()


class ComplexTest(BasicTest):
    def __init__(self, *args, **kwargs):
        print('ComplexTest.__init__')
        super(BasicTest, self).__init__(*args, **kwargs)

    def setUp(self):
        print('ComplexTest.setUp')
        super(BasicTest, self).tearDown()

    def tearDown(self):
        print('ComplexTest.tearDown')
        super(BasicTest, self).tearDown()

2) test.py

import unittest
import test_framework

class TestValueFunctions(test_framework.ComplexTest):
    def __init__(self, *args, **kwargs):
        print('TestValueFunctions.__init__')
        super(test_framework.ComplexTest, self).__init__(*args, **kwargs)

    def setUp(self):
        print('TestValueFunctions.setUp')
        super(test_framework.ComplexTest, self).tearDown()
        self.value = 4711

    def tearDown(self):
        print('TestValueFunctions.tearDown')
        super(test_framework.ComplexTest, self).tearDown()

    def test_value(self):
        print('TestValueFunctions.test_value')
        self.assertEqual(self.value, 4711)

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

3) 现在尝试运行时,我看到以下堆栈

TestValueFunctions.__init__
BasicTest.__init__
Traceback (most recent call last):
  File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test.py", line 23, in <module>
    unittest.main()
  File "C:\Python27\lib\unittest\main.py", line 94, in __init__
    self.parseArgs(argv)
  File "C:\Python27\lib\unittest\main.py", line 149, in parseArgs
    self.createTests()
  File "C:\Python27\lib\unittest\main.py", line 155, in createTests
    self.test = self.testLoader.loadTestsFromModule(self.module)
  File "C:\Python27\lib\unittest\loader.py", line 65, in loadTestsFromModule
    tests.append(self.loadTestsFromTestCase(obj))
  File "C:\Python27\lib\unittest\loader.py", line 56, in loadTestsFromTestCase
    loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
  File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test.py", line 7, in __init__
    super(test_framework.ComplexTest, self).__init__(*args, **kwargs)
  File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test_framework.py", line 6, in __init__
    super(unittest.TestCase, self).__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters

【问题讨论】:

  • super 的一大优势是您不必必须明确声明超类。正如您在错误中看到的那样,您使用该代码调用 object.__init__ 而不是 TestCase.__init__
  • 只有在 Python 3 中才能省略 super 的类参数。

标签: python constructor testcase


【解决方案1】:

确实你的init方法错了。

class BasicTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        print('BasicTest.__init__')
        super(unittest.TestCase, self).__init__(*args, **kwargs)

应该是:

class BasicTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        print('BasicTest.__init__')
        super(BasicTest, self).__init__(*args, **kwargs)

这将在 BasicTest 的母类(即 TestCase)上调用 __init__。这对于 setUp 和 tearDown 是一样的:

class BasicTest(unittest.TestCase):
    ...
    def setUp(self):
        print('BasicTest.setUp')
        super(BasicTest, self).setUp()

【讨论】:

  • 优秀:我似乎误解了 super,但现在它就像一个魅力。谢谢!
  • setUp 示例的最后一行应该是:super(BasicTest, self).setUp()。现在它会调用tearDown父方法,这不是逻辑。问题代码示例也是如此。
【解决方案2】:

super!谁知道它为什么会做任何事情。如果您在测试中停止使用它,而是显式调用您想要的父类,如下所示:

class BasicTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        print('BasicTest.__init__')
        unittest.TestCase.__init__(self, *args, **kwargs)

您最终会得到以下输出:

TestValueFunctions.__init__
ComplexTest.__init__
TestValueFunctions.setUp
ComplexTest.setUp
TestValueFunctions.test_value
TestValueFunctions.tearDown
ComplexTest.tearDown
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

见:Python's Super is nifty, but you can't use it

【讨论】:

  • 只有在您不希望它成为多重继承的一部分时才如此;否则,这会破坏事情并可能导致意外行为。
  • 它不会破坏事物。特别是因为unittest.TestCase 不使用超级。这是按照你想要调用的顺序显式调用你想要的代码的情况。
  • 不正确,如果你有这个和另一个子类 unittest.TestCase 的子类都作为这个类的直接父类,或者其他方式使得这在 mro 中比另一种方法更早结束,它会有问题。在这种特殊情况下可能不那么重要,但更一般地说,这不是一个好的选择(特别是如果它是对象的直接子类)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-20
  • 2013-10-05
  • 2013-06-20
  • 2013-12-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-16
相关资源
最近更新 更多