关于python:从TestCase派生一个类会引发两个错误

Deriving a class from TestCase throws two errors

我有一些基本的设置/拆卸代码,我想在一大堆单元测试中重用。 所以我明白了创建一些派生类以避免在每个测试类中重复代码。

这样做,我收到了两个奇怪的错误。 一,我无法解决。 这是无法解决的问题:

1
AttributeError: 'TestDesktopRootController' object has no attribute '_testMethodName'

这是我的基类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import unittest
import twill
import cherrypy
from cherrypy._cpwsgi import CPWSGIApp


class BaseControllerTest(unittest.TestCase):

    def __init__(self):
        self.controller = None

    def setUp(self):
        app = cherrypy.Application(self.controller)

        wsgi = CPWSGIApp(app)

        twill.add_wsgi_intercept('localhost', 8080, lambda : wsgi)

    def tearDown(self):
        twill.remove_wsgi_intercept('localhost', 8080)

这是我的派生类:

1
2
3
4
5
6
7
8
9
10
11
12
import twill
from base_controller_test import BaseControllerTest

class TestMyController(BaseControllerTest):

    def __init__(self, args):
        self.controller = MyController()
        BaseControllerTest.__init__(self)

    def test_root(self):
        script ="find 'Contacts'"
        twill.execute_string(script, initial_url='http://localhost:8080/')

另一个奇怪的错误是:

1
TypeError: __init__() takes exactly 1 argument (2 given)

对此的"解决方案"是将"args"一词添加到派生类中的__init__函数中。 有什么办法可以避免吗?

请记住,我在这一个中有两个错误。


这是因为你错误地覆盖__init__()。 几乎可以肯定,你根本不想覆盖__init__(); 你应该在setUp()中做所有事情。 我一直在使用unittest超过10年,我认为我没有超越__init__()

但是,如果您确实需要覆盖__init__(),请记住您无法控制构造函数的调用位置 - 框架会为您调用它。 所以你必须提供一个可以调用的签名。 从源代码(unittest/case.py),该签名是:

1
def __init__(self, methodName='runTest'):

这样做的安全方法是接受任何参数,然后将它们传递给基类。 这是一个有效的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class BaseTest(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        unittest.TestCase.__init__(self, *args, **kwargs)

    def setUp(self):
        print"Base.setUp()"

    def tearDown(self):
        print"Base.tearDown()"


class TestSomething(BaseTest):
    def __init__(self, *args, **kwargs):
        BaseTest.__init__(self, *args, **kwargs)
        self.controller = object()

    def test_silly(self):
        self.assertTrue(1+1 == 2)


BaseController__init__中,您需要像在TestMyController中一样调用unittest.TestCase__init__

从框架构造TestCase的调用可能是传递参数。 处理此类以获取类的最佳方法是:

1
2
3
4
class my_subclass(parentclass):
    def __init__(self, *args, **kw):
        parentclass.__init__(self, *args, **kw)
        ...