Подтвердить что ты не робот

Вывод класса из 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__ в производном классе. Есть ли способ избежать этого?

Помните, что у меня две ошибки в этом.

4b9b3361

Ответ 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)
        ...