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

ValueError: нет такого метода тестирования в <class 'myapp.tests.SessionTestCase'>: runTest

У меня есть тестовый пример:

class LoginTestCase(unittest.TestCase):
    ...

Я хотел бы использовать его в другом тестовом случае:

class EditProfileTestCase(unittest.TestCase):
  def __init__(self):
    self.t = LoginTestCase()
    self.t.login()

Это повышает:

ValueError: no such test method in <class 'LoginTest: runTest`

Я посмотрел на код unittest, где вызывается исключение, и похоже, что тесты не должны быть написаны таким образом. Есть ли стандартный способ написать что-то, что вы хотите протестировать, чтобы его можно было повторно использовать более поздними тестами? Или есть обходной путь?

Я добавил пустой метод runTest в LoginTest как сомнительный обходной путь.

4b9b3361

Ответ 1

unittest делает глубокую черную магию - если вы решите использовать ее для запуска ваших юнит-тестов (я это делаю, так как я могу использовать очень мощную батарею тестовых бегунов и интеграторов в систему сборки на мое рабочее место, но есть определенные альтернативы), вам лучше играть по своим правилам.

В этом случае я бы просто получил EditProfileTestCase из LoginTestCase (а не непосредственно из unittest.TestCase). Если есть некоторые части LoginTestCase, которые вы также хотите протестировать в другой среде EditProfileTestCase, а другие, которые у вас нет, просто реорганизуйте LoginTestCase в эти две части (возможно, используя несколько наследование), и если в двух случаях некоторые вещи должны произойти немного по-разному, выставляйте их во вспомогательные "методы крюка" (в шаблоне проектирования "Шаблонный метод" ) - я часто использую все эти подходы, чтобы уменьшить шаблон и увеличить повторное использование в сложных анализах я всегда пишу (если у меня есть модульное тестирование и <95%, я всегда чувствую себя действительно непросто - ниже 90%, я начинаю чувствовать физически больным; -).

Ответ 2

Путаница с "runTest" в основном основана на том, что это работает:

class MyTest(unittest.TestCase):
    def test_001(self):
        print "ok"

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

Таким образом, в этом классе нет "runTest", и все тестовые функции вызываются. Однако, если вы посмотрите на базовый класс "TestCase" (lib/python/unittest/case.py), вы обнаружите, что у него есть аргумент "methodName", по умолчанию "runTest", но у него нет реализации по умолчанию "def runTest"

class TestCase:
    def __init__(self, methodName='runTest'):

Причина, по которой unittest.main работает отлично, основана на том, что ей не нужен "runTest" - вы можете имитировать поведение, создав экземпляр подкласса TestCase для всех методов, которые у вас есть в вашем подклассе, - просто предоставьте имя в качестве первого аргумента:

class MyTest(unittest.TestCase):
    def test_001(self):
        print "ok"

if __name__ == "__main__":
    suite = unittest.TestSuite()
    for method in dir(MyTest):
       if method.startswith("test"):
          suite.addTest(MyTest(method))
    unittest.TextTestRunner().run(suite)

Ответ 3

Здесь некоторая ' глубокая черная магия':

suite = unittest.TestLoader().loadTestsFromTestCase(Test_MyTests)
unittest.TextTestRunner(verbosity=3).run(suite)

Очень удобно, если вы просто хотите протестировать запуск своих модульных тестов из оболочки (т.е. IPython).

Ответ 4

Если вы не возражаете редактировать код модуля unit test напрямую, простое исправление заключается в том, чтобы добавить в case.py класс TestCase новый метод под названием runTest, который делает ничего.

Файл для редактирования находится под pythoninstall\Lib\unittest\case.py

def runTest(self):
    pass

Это остановит вас при получении этой ошибки.

Ответ 5

Ответ Guido почти есть, но это не объясняет. Мне нужно было посмотреть код unittest, чтобы понять поток.

Скажите, что у вас есть следующее.

import unittest

class MyTestCase(unittest.TestCase):

  def testA(self):
    pass

  def testB(self):
    pass

Когда вы используете unittest.main(), он попытается обнаружить тестовые примеры в текущем модуле. Важным кодом является unittest.loader.TestLoader.loadTestsFromTestCase.

def loadTestsFromTestCase(self, testCaseClass):
  # ...

  # This will look in class' callable attributes that start 
  # with 'test',  and return their names sorted.
  testCaseNames = self.getTestCaseNames(testCaseClass)

  # If there no test to run, look if the case has the default method.
  if not testCaseNames and hasattr(testCaseClass, 'runTest'):
    testCaseNames = ['runTest']

  # Create TestSuite instance having test case instance per test method.
  loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))

  return loaded_suite

Что последний делает, преобразует класс тестового случая в тестовый набор, который содержит экземпляры класса для его тестового метода. То есть мой пример будет преобразован в unittest.suite.TestSuite([MyTestCase('testA'), MyTestCase('testB')]). Поэтому, если вы хотите создать тестовый пример вручную, вам нужно сделать то же самое.

Ответ 6

@dmvianna ответил, что я очень близок к возможности запуска unittest в jupyter (ipython) ноутбуке, но мне пришлось сделать немного больше. Если бы я написал только следующее:

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

suite = unittest.TestLoader().loadTestsFromModule (TestStringMethods)
unittest.TextTestRunner().run(suite)

Я получил


Ran 0 тестов в 0.000s

OK

Он не сломан, но он не запускает никаких тестов! Если я создал экземпляр класса

suite = unittest.TestLoader().loadTestsFromModule (TestStringMethods())

(обратите внимание на parens в конце строки, что единственное изменение) я получил


Traceback ValueError (последний последний вызов)  в() ---- > 1 suite = unittest.TestLoader(). LoadTestsFromModule (TestStringMethods())

/usr/lib/python2.7/unittest/case.pyc в init (self, methodName)     189 кроме AttributeError:     190 повышают значение ValueError ( "нет такого метода теста в% s:% s" % → 191 (self. класс, methodName))     192 self._testMethodDoc = testMethod. doc    193 self._cleanups = []

ValueError: нет такого метода тестирования в: runTest

Исправление теперь достаточно понятно: добавьте runTest в тестовый класс:

class TestStringMethods(unittest.TestCase):

    def runTest(self):
        test_upper (self)
        test_isupper (self)
        test_split (self)

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

suite = unittest.TestLoader().loadTestsFromModule (TestStringMethods())
unittest.TextTestRunner().run(suite)

Ran 3 тесты в 0.002s

OK

Он также работает правильно (и запускает 3 теста), если мой runTest просто pass es, как было предложено @Darren.

Это немного суетливый, требующий ручного труда с моей стороны, но он также более явный, и что добродетель Питона, не так ли?

Я не смог получить какие-либо из этих методов, вызвав unittest.main с явными аргументами отсюда или из этого связанного вопроса Невозможно запустить основную функцию unittest в ноутбуке ipython/jupyter работать внутри ноутбука jupyter, но я снова на дороге с полным баком газа.