Вывод класса из TestCase вызывает две ошибки
У меня есть базовый код установки/разрыва, который я хочу повторно использовать во всей группе модульных тестов. Поэтому я получил яркую идею создания некоторых производных классов, чтобы избежать повторения кода в каждом тестовом классе.
При этом я получил две странные ошибки. Во-первых, я не могу решить. Вот неразрешимый:
AttributeError: 'TestDesktopRootController' object has no attribute '_testMethodName'
Вот мой базовый класс:
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)
И вот мой производный класс:
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/')
Другая странная ошибка:
TypeError: __init__() takes exactly 1 argument (2 given)
"Решение" - это добавить слово "args" к моей функции __init__
в производном классе. Есть ли способ избежать этого?
Помните, что у меня две ошибки в этом.
Ответы
Ответ 1
Это потому, что вы неправильно переопределяете __init__()
. Почти наверняка вы не хотите переопределять __init__()
вообще; вы должны сделать все в setUp()
. Я использовал unittest
в течение > 10 лет, и я не думаю, что когда-либо переопределял __init__()
.
Однако, если вам действительно нужно переопределить __init__()
, помните, что вы не контролируете, где вызывается ваш конструктор, - инфраструктура вызывает его для вас. Поэтому вы должны предоставить подпись, которую он может вызвать. Из исходного кода (unittest/case.py
) эта подпись:
def __init__(self, methodName='runTest'):
Безопасный способ сделать это - принять любые аргументы и просто передать их в базовый класс. Вот работающая реализация:
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)
Ответ 2
В BaseController
__init__
вам нужно вызвать unittest.TestCase
__init__
так же, как в TestMyController
.
Призыв к созданию TestCase из фреймворка может передавать аргумент. Лучший способ справиться с этим для получения классов:
class my_subclass(parentclass):
def __init__(self, *args, **kw):
parentclass.__init__(self, *args, **kw)
...